wasmtime/runtime/component/
values.rs

1use crate::ValRaw;
2use crate::component::ResourceAny;
3use crate::component::func::{Lift, LiftContext, Lower, LowerContext, desc};
4use crate::prelude::*;
5use core::mem::MaybeUninit;
6use core::slice::{Iter, IterMut};
7use wasmtime_component_util::{DiscriminantSize, FlagsSize};
8use wasmtime_environ::component::{
9    CanonicalAbiInfo, InterfaceType, TypeEnum, TypeFlags, TypeListIndex, TypeOption, TypeResult,
10    TypeVariant, VariantInfo,
11};
12
13/// Represents possible runtime values which a component function can either
14/// consume or produce
15///
16/// This is a dynamic representation of possible values in the component model.
17/// Note that this is not an efficient representation but is instead intended to
18/// be a flexible and somewhat convenient representation. The most efficient
19/// representation of component model types is to use the `bindgen!` macro to
20/// generate native Rust types with specialized liftings and lowerings.
21///
22/// This type is used in conjunction with [`Func::call`] for example if the
23/// signature of a component is not statically known ahead of time.
24///
25/// # Equality and `Val`
26///
27/// This type implements both the Rust `PartialEq` and `Eq` traits. This type
28/// additionally contains values which are not necessarily easily equated,
29/// however, such as floats (`Float32` and `Float64`) and resources. Equality
30/// does require that two values have the same type, and then these cases are
31/// handled as:
32///
33/// * Floats are tested if they are "semantically the same" meaning all NaN
34///   values are equal to all other NaN values. Additionally zero values must be
35///   exactly the same, so positive zero is not equal to negative zero. The
36///   primary use case at this time is fuzzing-related equality which this is
37///   sufficient for.
38///
39/// * Resources are tested if their types and indices into the host table are
40///   equal. This does not compare the underlying representation so borrows of
41///   the same guest resource are not considered equal. This additionally
42///   doesn't go further and test for equality in the guest itself (for example
43///   two different heap allocations of `Box<u32>` can be equal in normal Rust
44///   if they contain the same value, but will never be considered equal when
45///   compared as `Val::Resource`s).
46///
47/// In general if a strict guarantee about equality is required here it's
48/// recommended to "build your own" as this equality intended for fuzzing
49/// Wasmtime may not be suitable for you.
50///
51/// # Component model types and `Val`
52///
53/// The `Val` type here does not contain enough information to say what the
54/// component model type of a `Val` is. This is instead more of an AST of sorts.
55/// For example the `Val::Enum` only carries information about a single
56/// discriminant, not the entire enumeration or what it's a discriminant of.
57///
58/// This means that when a `Val` is passed to Wasmtime, for example as a
59/// function parameter when calling a function or as a return value from an
60/// host-defined imported function, then it must pass a type-check. Instances of
61/// `Val` are type-checked against what's required by the component itself.
62///
63/// [`Func::call`]: crate::component::Func::call
64#[derive(Debug, Clone)]
65#[allow(missing_docs)]
66pub enum Val {
67    Bool(bool),
68    S8(i8),
69    U8(u8),
70    S16(i16),
71    U16(u16),
72    S32(i32),
73    U32(u32),
74    S64(i64),
75    U64(u64),
76    Float32(f32),
77    Float64(f64),
78    Char(char),
79    String(String),
80    List(Vec<Val>),
81    Record(Vec<(String, Val)>),
82    Tuple(Vec<Val>),
83    Variant(String, Option<Box<Val>>),
84    Enum(String),
85    Option(Option<Box<Val>>),
86    Result(Result<Option<Box<Val>>, Option<Box<Val>>>),
87    Flags(Vec<String>),
88    Resource(ResourceAny),
89}
90
91impl Val {
92    /// Deserialize a value of this type from core Wasm stack values.
93    pub(crate) fn lift(
94        cx: &mut LiftContext<'_>,
95        ty: InterfaceType,
96        src: &mut Iter<'_, ValRaw>,
97    ) -> Result<Val> {
98        Ok(match ty {
99            InterfaceType::Bool => Val::Bool(bool::linear_lift_from_flat(cx, ty, next(src))?),
100            InterfaceType::S8 => Val::S8(i8::linear_lift_from_flat(cx, ty, next(src))?),
101            InterfaceType::U8 => Val::U8(u8::linear_lift_from_flat(cx, ty, next(src))?),
102            InterfaceType::S16 => Val::S16(i16::linear_lift_from_flat(cx, ty, next(src))?),
103            InterfaceType::U16 => Val::U16(u16::linear_lift_from_flat(cx, ty, next(src))?),
104            InterfaceType::S32 => Val::S32(i32::linear_lift_from_flat(cx, ty, next(src))?),
105            InterfaceType::U32 => Val::U32(u32::linear_lift_from_flat(cx, ty, next(src))?),
106            InterfaceType::S64 => Val::S64(i64::linear_lift_from_flat(cx, ty, next(src))?),
107            InterfaceType::U64 => Val::U64(u64::linear_lift_from_flat(cx, ty, next(src))?),
108            InterfaceType::Float32 => Val::Float32(f32::linear_lift_from_flat(cx, ty, next(src))?),
109            InterfaceType::Float64 => Val::Float64(f64::linear_lift_from_flat(cx, ty, next(src))?),
110            InterfaceType::Char => Val::Char(char::linear_lift_from_flat(cx, ty, next(src))?),
111            InterfaceType::Own(_) | InterfaceType::Borrow(_) => {
112                Val::Resource(ResourceAny::linear_lift_from_flat(cx, ty, next(src))?)
113            }
114            InterfaceType::String => Val::String(<_>::linear_lift_from_flat(
115                cx,
116                ty,
117                &[*next(src), *next(src)],
118            )?),
119            InterfaceType::List(i) => {
120                // FIXME(#4311): needs memory64 treatment
121                let ptr = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize;
122                let len = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize;
123                load_list(cx, i, ptr, len)?
124            }
125            InterfaceType::Record(i) => Val::Record(
126                cx.types[i]
127                    .fields
128                    .iter()
129                    .map(|field| {
130                        let val = Self::lift(cx, field.ty, src)?;
131                        Ok((field.name.to_string(), val))
132                    })
133                    .collect::<Result<_>>()?,
134            ),
135            InterfaceType::Tuple(i) => Val::Tuple(
136                cx.types[i]
137                    .types
138                    .iter()
139                    .map(|ty| Self::lift(cx, *ty, src))
140                    .collect::<Result<_>>()?,
141            ),
142            InterfaceType::Variant(i) => {
143                let vty = &cx.types[i];
144                let (discriminant, value) = lift_variant(
145                    cx,
146                    cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
147                    vty.cases.values().copied(),
148                    src,
149                )?;
150
151                let (k, _) = vty.cases.get_index(discriminant as usize).unwrap();
152                Val::Variant(k.clone(), value)
153            }
154            InterfaceType::Enum(i) => {
155                let ety = &cx.types[i];
156                let (discriminant, _) = lift_variant(
157                    cx,
158                    cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
159                    ety.names.iter().map(|_| None),
160                    src,
161                )?;
162
163                Val::Enum(ety.names[discriminant as usize].clone())
164            }
165            InterfaceType::Option(i) => {
166                let (_discriminant, value) = lift_variant(
167                    cx,
168                    cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
169                    [None, Some(cx.types[i].ty)].into_iter(),
170                    src,
171                )?;
172
173                Val::Option(value)
174            }
175            InterfaceType::Result(i) => {
176                let result_ty = &cx.types[i];
177                let (discriminant, value) = lift_variant(
178                    cx,
179                    cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
180                    [result_ty.ok, result_ty.err].into_iter(),
181                    src,
182                )?;
183
184                Val::Result(if discriminant == 0 {
185                    Ok(value)
186                } else {
187                    Err(value)
188                })
189            }
190            InterfaceType::Flags(i) => {
191                let u32_count = cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap();
192                let ty = &cx.types[i];
193                let mut flags = Vec::new();
194                for i in 0..u32::try_from(u32_count).unwrap() {
195                    push_flags(
196                        ty,
197                        &mut flags,
198                        i * 32,
199                        u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))?,
200                    );
201                }
202
203                Val::Flags(flags)
204            }
205            InterfaceType::Future(_)
206            | InterfaceType::Stream(_)
207            | InterfaceType::ErrorContext(_) => todo!(),
208        })
209    }
210
211    /// Deserialize a value of this type from the heap.
212    pub(crate) fn load(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Val> {
213        Ok(match ty {
214            InterfaceType::Bool => Val::Bool(bool::linear_lift_from_memory(cx, ty, bytes)?),
215            InterfaceType::S8 => Val::S8(i8::linear_lift_from_memory(cx, ty, bytes)?),
216            InterfaceType::U8 => Val::U8(u8::linear_lift_from_memory(cx, ty, bytes)?),
217            InterfaceType::S16 => Val::S16(i16::linear_lift_from_memory(cx, ty, bytes)?),
218            InterfaceType::U16 => Val::U16(u16::linear_lift_from_memory(cx, ty, bytes)?),
219            InterfaceType::S32 => Val::S32(i32::linear_lift_from_memory(cx, ty, bytes)?),
220            InterfaceType::U32 => Val::U32(u32::linear_lift_from_memory(cx, ty, bytes)?),
221            InterfaceType::S64 => Val::S64(i64::linear_lift_from_memory(cx, ty, bytes)?),
222            InterfaceType::U64 => Val::U64(u64::linear_lift_from_memory(cx, ty, bytes)?),
223            InterfaceType::Float32 => Val::Float32(f32::linear_lift_from_memory(cx, ty, bytes)?),
224            InterfaceType::Float64 => Val::Float64(f64::linear_lift_from_memory(cx, ty, bytes)?),
225            InterfaceType::Char => Val::Char(char::linear_lift_from_memory(cx, ty, bytes)?),
226            InterfaceType::String => Val::String(<_>::linear_lift_from_memory(cx, ty, bytes)?),
227            InterfaceType::Own(_) | InterfaceType::Borrow(_) => {
228                Val::Resource(ResourceAny::linear_lift_from_memory(cx, ty, bytes)?)
229            }
230            InterfaceType::List(i) => {
231                // FIXME(#4311): needs memory64 treatment
232                let ptr = u32::from_le_bytes(bytes[..4].try_into().unwrap()) as usize;
233                let len = u32::from_le_bytes(bytes[4..].try_into().unwrap()) as usize;
234                load_list(cx, i, ptr, len)?
235            }
236
237            InterfaceType::Record(i) => {
238                let mut offset = 0;
239                let fields = cx.types[i].fields.iter();
240                Val::Record(
241                    fields
242                        .map(|field| -> Result<(String, Val)> {
243                            let abi = cx.types.canonical_abi(&field.ty);
244                            let offset = abi.next_field32(&mut offset);
245                            let offset = usize::try_from(offset).unwrap();
246                            let size = usize::try_from(abi.size32).unwrap();
247                            Ok((
248                                field.name.to_string(),
249                                Val::load(cx, field.ty, &bytes[offset..][..size])?,
250                            ))
251                        })
252                        .collect::<Result<_>>()?,
253                )
254            }
255            InterfaceType::Tuple(i) => {
256                let types = cx.types[i].types.iter().copied();
257                let mut offset = 0;
258                Val::Tuple(
259                    types
260                        .map(|ty| {
261                            let abi = cx.types.canonical_abi(&ty);
262                            let offset = abi.next_field32(&mut offset);
263                            let offset = usize::try_from(offset).unwrap();
264                            let size = usize::try_from(abi.size32).unwrap();
265                            Val::load(cx, ty, &bytes[offset..][..size])
266                        })
267                        .collect::<Result<_>>()?,
268                )
269            }
270            InterfaceType::Variant(i) => {
271                let ty = &cx.types[i];
272                let (discriminant, value) =
273                    load_variant(cx, &ty.info, ty.cases.values().copied(), bytes)?;
274
275                let (k, _) = ty.cases.get_index(discriminant as usize).unwrap();
276                Val::Variant(k.clone(), value)
277            }
278            InterfaceType::Enum(i) => {
279                let ty = &cx.types[i];
280                let (discriminant, _) =
281                    load_variant(cx, &ty.info, ty.names.iter().map(|_| None), bytes)?;
282
283                Val::Enum(ty.names[discriminant as usize].clone())
284            }
285            InterfaceType::Option(i) => {
286                let ty = &cx.types[i];
287                let (_discriminant, value) =
288                    load_variant(cx, &ty.info, [None, Some(ty.ty)].into_iter(), bytes)?;
289
290                Val::Option(value)
291            }
292            InterfaceType::Result(i) => {
293                let ty = &cx.types[i];
294                let (discriminant, value) =
295                    load_variant(cx, &ty.info, [ty.ok, ty.err].into_iter(), bytes)?;
296
297                Val::Result(if discriminant == 0 {
298                    Ok(value)
299                } else {
300                    Err(value)
301                })
302            }
303            InterfaceType::Flags(i) => {
304                let ty = &cx.types[i];
305                let mut flags = Vec::new();
306                match FlagsSize::from_count(ty.names.len()) {
307                    FlagsSize::Size0 => {}
308                    FlagsSize::Size1 => {
309                        let bits = u8::linear_lift_from_memory(cx, InterfaceType::U8, bytes)?;
310                        push_flags(ty, &mut flags, 0, u32::from(bits));
311                    }
312                    FlagsSize::Size2 => {
313                        let bits = u16::linear_lift_from_memory(cx, InterfaceType::U16, bytes)?;
314                        push_flags(ty, &mut flags, 0, u32::from(bits));
315                    }
316                    FlagsSize::Size4Plus(n) => {
317                        for i in 0..n {
318                            let bits = u32::linear_lift_from_memory(
319                                cx,
320                                InterfaceType::U32,
321                                &bytes[usize::from(i) * 4..][..4],
322                            )?;
323                            push_flags(ty, &mut flags, u32::from(i) * 32, bits);
324                        }
325                    }
326                }
327                Val::Flags(flags)
328            }
329            InterfaceType::Future(_)
330            | InterfaceType::Stream(_)
331            | InterfaceType::ErrorContext(_) => todo!(),
332        })
333    }
334
335    /// Serialize this value as core Wasm stack values.
336    pub(crate) fn lower<T>(
337        &self,
338        cx: &mut LowerContext<'_, T>,
339        ty: InterfaceType,
340        dst: &mut IterMut<'_, MaybeUninit<ValRaw>>,
341    ) -> Result<()> {
342        match (ty, self) {
343            (InterfaceType::Bool, Val::Bool(value)) => {
344                value.linear_lower_to_flat(cx, ty, next_mut(dst))
345            }
346            (InterfaceType::Bool, _) => unexpected(ty, self),
347            (InterfaceType::S8, Val::S8(value)) => {
348                value.linear_lower_to_flat(cx, ty, next_mut(dst))
349            }
350            (InterfaceType::S8, _) => unexpected(ty, self),
351            (InterfaceType::U8, Val::U8(value)) => {
352                value.linear_lower_to_flat(cx, ty, next_mut(dst))
353            }
354            (InterfaceType::U8, _) => unexpected(ty, self),
355            (InterfaceType::S16, Val::S16(value)) => {
356                value.linear_lower_to_flat(cx, ty, next_mut(dst))
357            }
358            (InterfaceType::S16, _) => unexpected(ty, self),
359            (InterfaceType::U16, Val::U16(value)) => {
360                value.linear_lower_to_flat(cx, ty, next_mut(dst))
361            }
362            (InterfaceType::U16, _) => unexpected(ty, self),
363            (InterfaceType::S32, Val::S32(value)) => {
364                value.linear_lower_to_flat(cx, ty, next_mut(dst))
365            }
366            (InterfaceType::S32, _) => unexpected(ty, self),
367            (InterfaceType::U32, Val::U32(value)) => {
368                value.linear_lower_to_flat(cx, ty, next_mut(dst))
369            }
370            (InterfaceType::U32, _) => unexpected(ty, self),
371            (InterfaceType::S64, Val::S64(value)) => {
372                value.linear_lower_to_flat(cx, ty, next_mut(dst))
373            }
374            (InterfaceType::S64, _) => unexpected(ty, self),
375            (InterfaceType::U64, Val::U64(value)) => {
376                value.linear_lower_to_flat(cx, ty, next_mut(dst))
377            }
378            (InterfaceType::U64, _) => unexpected(ty, self),
379            (InterfaceType::Float32, Val::Float32(value)) => {
380                value.linear_lower_to_flat(cx, ty, next_mut(dst))
381            }
382            (InterfaceType::Float32, _) => unexpected(ty, self),
383            (InterfaceType::Float64, Val::Float64(value)) => {
384                value.linear_lower_to_flat(cx, ty, next_mut(dst))
385            }
386            (InterfaceType::Float64, _) => unexpected(ty, self),
387            (InterfaceType::Char, Val::Char(value)) => {
388                value.linear_lower_to_flat(cx, ty, next_mut(dst))
389            }
390            (InterfaceType::Char, _) => unexpected(ty, self),
391            // NB: `lower` on `ResourceAny` does its own type-checking, so skip
392            // looking at it here.
393            (InterfaceType::Borrow(_) | InterfaceType::Own(_), Val::Resource(value)) => {
394                value.linear_lower_to_flat(cx, ty, next_mut(dst))
395            }
396            (InterfaceType::Borrow(_) | InterfaceType::Own(_), _) => unexpected(ty, self),
397            (InterfaceType::String, Val::String(value)) => {
398                let my_dst = &mut MaybeUninit::<[ValRaw; 2]>::uninit();
399                value.linear_lower_to_flat(cx, ty, my_dst)?;
400                let my_dst = unsafe { my_dst.assume_init() };
401                next_mut(dst).write(my_dst[0]);
402                next_mut(dst).write(my_dst[1]);
403                Ok(())
404            }
405            (InterfaceType::String, _) => unexpected(ty, self),
406            (InterfaceType::List(ty), Val::List(values)) => {
407                let ty = &cx.types[ty];
408                let (ptr, len) = lower_list(cx, ty.element, values)?;
409                next_mut(dst).write(ValRaw::i64(ptr as i64));
410                next_mut(dst).write(ValRaw::i64(len as i64));
411                Ok(())
412            }
413            (InterfaceType::List(_), _) => unexpected(ty, self),
414            (InterfaceType::Record(ty), Val::Record(values)) => {
415                let ty = &cx.types[ty];
416                if ty.fields.len() != values.len() {
417                    bail!("expected {} fields, got {}", ty.fields.len(), values.len());
418                }
419                for ((name, value), field) in values.iter().zip(ty.fields.iter()) {
420                    if *name != field.name {
421                        bail!("expected field `{}`, got `{name}`", field.name);
422                    }
423                    value.lower(cx, field.ty, dst)?;
424                }
425                Ok(())
426            }
427            (InterfaceType::Record(_), _) => unexpected(ty, self),
428            (InterfaceType::Tuple(ty), Val::Tuple(values)) => {
429                let ty = &cx.types[ty];
430                if ty.types.len() != values.len() {
431                    bail!("expected {} types, got {}", ty.types.len(), values.len());
432                }
433                for (value, ty) in values.iter().zip(ty.types.iter()) {
434                    value.lower(cx, *ty, dst)?;
435                }
436                Ok(())
437            }
438            (InterfaceType::Tuple(_), _) => unexpected(ty, self),
439            (InterfaceType::Variant(ty), Val::Variant(n, v)) => {
440                GenericVariant::variant(&cx.types[ty], n, v)?.lower(cx, dst)
441            }
442            (InterfaceType::Variant(_), _) => unexpected(ty, self),
443            (InterfaceType::Option(ty), Val::Option(v)) => {
444                GenericVariant::option(&cx.types[ty], v).lower(cx, dst)
445            }
446            (InterfaceType::Option(_), _) => unexpected(ty, self),
447            (InterfaceType::Result(ty), Val::Result(v)) => {
448                GenericVariant::result(&cx.types[ty], v)?.lower(cx, dst)
449            }
450            (InterfaceType::Result(_), _) => unexpected(ty, self),
451            (InterfaceType::Enum(ty), Val::Enum(discriminant)) => {
452                let discriminant = get_enum_discriminant(&cx.types[ty], discriminant)?;
453                next_mut(dst).write(ValRaw::u32(discriminant));
454                Ok(())
455            }
456            (InterfaceType::Enum(_), _) => unexpected(ty, self),
457            (InterfaceType::Flags(ty), Val::Flags(value)) => {
458                let ty = &cx.types[ty];
459                let storage = flags_to_storage(ty, value)?;
460                for value in storage {
461                    next_mut(dst).write(ValRaw::u32(value));
462                }
463                Ok(())
464            }
465            (InterfaceType::Flags(_), _) => unexpected(ty, self),
466            (InterfaceType::Future(_), _)
467            | (InterfaceType::Stream(_), _)
468            | (InterfaceType::ErrorContext(_), _) => todo!(),
469        }
470    }
471
472    /// Serialize this value to the heap at the specified memory location.
473    pub(crate) fn store<T>(
474        &self,
475        cx: &mut LowerContext<'_, T>,
476        ty: InterfaceType,
477        offset: usize,
478    ) -> Result<()> {
479        debug_assert!(offset % usize::try_from(cx.types.canonical_abi(&ty).align32)? == 0);
480
481        match (ty, self) {
482            (InterfaceType::Bool, Val::Bool(value)) => value.linear_lower_to_memory(cx, ty, offset),
483            (InterfaceType::Bool, _) => unexpected(ty, self),
484            (InterfaceType::U8, Val::U8(value)) => value.linear_lower_to_memory(cx, ty, offset),
485            (InterfaceType::U8, _) => unexpected(ty, self),
486            (InterfaceType::S8, Val::S8(value)) => value.linear_lower_to_memory(cx, ty, offset),
487            (InterfaceType::S8, _) => unexpected(ty, self),
488            (InterfaceType::U16, Val::U16(value)) => value.linear_lower_to_memory(cx, ty, offset),
489            (InterfaceType::U16, _) => unexpected(ty, self),
490            (InterfaceType::S16, Val::S16(value)) => value.linear_lower_to_memory(cx, ty, offset),
491            (InterfaceType::S16, _) => unexpected(ty, self),
492            (InterfaceType::U32, Val::U32(value)) => value.linear_lower_to_memory(cx, ty, offset),
493            (InterfaceType::U32, _) => unexpected(ty, self),
494            (InterfaceType::S32, Val::S32(value)) => value.linear_lower_to_memory(cx, ty, offset),
495            (InterfaceType::S32, _) => unexpected(ty, self),
496            (InterfaceType::U64, Val::U64(value)) => value.linear_lower_to_memory(cx, ty, offset),
497            (InterfaceType::U64, _) => unexpected(ty, self),
498            (InterfaceType::S64, Val::S64(value)) => value.linear_lower_to_memory(cx, ty, offset),
499            (InterfaceType::S64, _) => unexpected(ty, self),
500            (InterfaceType::Float32, Val::Float32(value)) => {
501                value.linear_lower_to_memory(cx, ty, offset)
502            }
503            (InterfaceType::Float32, _) => unexpected(ty, self),
504            (InterfaceType::Float64, Val::Float64(value)) => {
505                value.linear_lower_to_memory(cx, ty, offset)
506            }
507            (InterfaceType::Float64, _) => unexpected(ty, self),
508            (InterfaceType::Char, Val::Char(value)) => value.linear_lower_to_memory(cx, ty, offset),
509            (InterfaceType::Char, _) => unexpected(ty, self),
510            (InterfaceType::String, Val::String(value)) => {
511                value.linear_lower_to_memory(cx, ty, offset)
512            }
513            (InterfaceType::String, _) => unexpected(ty, self),
514
515            // NB: resources do type-checking when they lower.
516            (InterfaceType::Borrow(_) | InterfaceType::Own(_), Val::Resource(value)) => {
517                value.linear_lower_to_memory(cx, ty, offset)
518            }
519            (InterfaceType::Borrow(_) | InterfaceType::Own(_), _) => unexpected(ty, self),
520            (InterfaceType::List(ty), Val::List(values)) => {
521                let ty = &cx.types[ty];
522                let (ptr, len) = lower_list(cx, ty.element, values)?;
523                // FIXME(#4311): needs memory64 handling
524                *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes();
525                *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes();
526                Ok(())
527            }
528            (InterfaceType::List(_), _) => unexpected(ty, self),
529            (InterfaceType::Record(ty), Val::Record(values)) => {
530                let ty = &cx.types[ty];
531                if ty.fields.len() != values.len() {
532                    bail!("expected {} fields, got {}", ty.fields.len(), values.len());
533                }
534                let mut offset = offset;
535                for ((name, value), field) in values.iter().zip(ty.fields.iter()) {
536                    if *name != field.name {
537                        bail!("expected field `{}`, got `{name}`", field.name);
538                    }
539                    value.store(
540                        cx,
541                        field.ty,
542                        cx.types
543                            .canonical_abi(&field.ty)
544                            .next_field32_size(&mut offset),
545                    )?;
546                }
547                Ok(())
548            }
549            (InterfaceType::Record(_), _) => unexpected(ty, self),
550            (InterfaceType::Tuple(ty), Val::Tuple(values)) => {
551                let ty = &cx.types[ty];
552                if ty.types.len() != values.len() {
553                    bail!("expected {} types, got {}", ty.types.len(), values.len());
554                }
555                let mut offset = offset;
556                for (value, ty) in values.iter().zip(ty.types.iter()) {
557                    value.store(
558                        cx,
559                        *ty,
560                        cx.types.canonical_abi(ty).next_field32_size(&mut offset),
561                    )?;
562                }
563                Ok(())
564            }
565            (InterfaceType::Tuple(_), _) => unexpected(ty, self),
566
567            (InterfaceType::Variant(ty), Val::Variant(n, v)) => {
568                GenericVariant::variant(&cx.types[ty], n, v)?.store(cx, offset)
569            }
570            (InterfaceType::Variant(_), _) => unexpected(ty, self),
571            (InterfaceType::Enum(ty), Val::Enum(v)) => {
572                GenericVariant::enum_(&cx.types[ty], v)?.store(cx, offset)
573            }
574            (InterfaceType::Enum(_), _) => unexpected(ty, self),
575            (InterfaceType::Option(ty), Val::Option(v)) => {
576                GenericVariant::option(&cx.types[ty], v).store(cx, offset)
577            }
578            (InterfaceType::Option(_), _) => unexpected(ty, self),
579            (InterfaceType::Result(ty), Val::Result(v)) => {
580                GenericVariant::result(&cx.types[ty], v)?.store(cx, offset)
581            }
582            (InterfaceType::Result(_), _) => unexpected(ty, self),
583
584            (InterfaceType::Flags(ty), Val::Flags(flags)) => {
585                let ty = &cx.types[ty];
586                let storage = flags_to_storage(ty, flags)?;
587                match FlagsSize::from_count(ty.names.len()) {
588                    FlagsSize::Size0 => {}
589                    FlagsSize::Size1 => u8::try_from(storage[0]).unwrap().linear_lower_to_memory(
590                        cx,
591                        InterfaceType::U8,
592                        offset,
593                    )?,
594                    FlagsSize::Size2 => u16::try_from(storage[0]).unwrap().linear_lower_to_memory(
595                        cx,
596                        InterfaceType::U16,
597                        offset,
598                    )?,
599                    FlagsSize::Size4Plus(_) => {
600                        let mut offset = offset;
601                        for value in storage {
602                            value.linear_lower_to_memory(cx, InterfaceType::U32, offset)?;
603                            offset += 4;
604                        }
605                    }
606                }
607                Ok(())
608            }
609            (InterfaceType::Flags(_), _) => unexpected(ty, self),
610            (InterfaceType::Future(_), _)
611            | (InterfaceType::Stream(_), _)
612            | (InterfaceType::ErrorContext(_), _) => todo!(),
613        }
614    }
615
616    fn desc(&self) -> &'static str {
617        match self {
618            Val::Bool(_) => "bool",
619            Val::U8(_) => "u8",
620            Val::S8(_) => "s8",
621            Val::U16(_) => "u16",
622            Val::S16(_) => "s16",
623            Val::U32(_) => "u32",
624            Val::S32(_) => "s32",
625            Val::U64(_) => "u64",
626            Val::S64(_) => "s64",
627            Val::Float32(_) => "f32",
628            Val::Float64(_) => "f64",
629            Val::Char(_) => "char",
630            Val::List(_) => "list",
631            Val::String(_) => "string",
632            Val::Record(_) => "record",
633            Val::Enum(_) => "enum",
634            Val::Variant(..) => "variant",
635            Val::Tuple(_) => "tuple",
636            Val::Option(_) => "option",
637            Val::Result(_) => "result",
638            Val::Resource(_) => "resource",
639            Val::Flags(_) => "flags",
640        }
641    }
642
643    /// Deserialize a [`Val`] from its [`crate::component::wasm_wave`] encoding. Deserialization
644    /// requires a target [`crate::component::Type`].
645    #[cfg(feature = "wave")]
646    pub fn from_wave(ty: &crate::component::Type, s: &str) -> Result<Self> {
647        Ok(wasm_wave::from_str(ty, s)?)
648    }
649
650    /// Serialize a [`Val`] to its [`crate::component::wasm_wave`] encoding.
651    #[cfg(feature = "wave")]
652    pub fn to_wave(&self) -> Result<String> {
653        Ok(wasm_wave::to_string(self)?)
654    }
655}
656
657impl PartialEq for Val {
658    fn eq(&self, other: &Self) -> bool {
659        match (self, other) {
660            // IEEE 754 equality considers NaN inequal to NaN and negative zero
661            // equal to positive zero, however we do the opposite here, because
662            // this logic is used by testing and fuzzing, which want to know
663            // whether two values are semantically the same, rather than
664            // numerically equal.
665            (Self::Float32(l), Self::Float32(r)) => {
666                (*l != 0.0 && l == r)
667                    || (*l == 0.0 && l.to_bits() == r.to_bits())
668                    || (l.is_nan() && r.is_nan())
669            }
670            (Self::Float32(_), _) => false,
671            (Self::Float64(l), Self::Float64(r)) => {
672                (*l != 0.0 && l == r)
673                    || (*l == 0.0 && l.to_bits() == r.to_bits())
674                    || (l.is_nan() && r.is_nan())
675            }
676            (Self::Float64(_), _) => false,
677
678            (Self::Bool(l), Self::Bool(r)) => l == r,
679            (Self::Bool(_), _) => false,
680            (Self::S8(l), Self::S8(r)) => l == r,
681            (Self::S8(_), _) => false,
682            (Self::U8(l), Self::U8(r)) => l == r,
683            (Self::U8(_), _) => false,
684            (Self::S16(l), Self::S16(r)) => l == r,
685            (Self::S16(_), _) => false,
686            (Self::U16(l), Self::U16(r)) => l == r,
687            (Self::U16(_), _) => false,
688            (Self::S32(l), Self::S32(r)) => l == r,
689            (Self::S32(_), _) => false,
690            (Self::U32(l), Self::U32(r)) => l == r,
691            (Self::U32(_), _) => false,
692            (Self::S64(l), Self::S64(r)) => l == r,
693            (Self::S64(_), _) => false,
694            (Self::U64(l), Self::U64(r)) => l == r,
695            (Self::U64(_), _) => false,
696            (Self::Char(l), Self::Char(r)) => l == r,
697            (Self::Char(_), _) => false,
698            (Self::String(l), Self::String(r)) => l == r,
699            (Self::String(_), _) => false,
700            (Self::List(l), Self::List(r)) => l == r,
701            (Self::List(_), _) => false,
702            (Self::Record(l), Self::Record(r)) => l == r,
703            (Self::Record(_), _) => false,
704            (Self::Tuple(l), Self::Tuple(r)) => l == r,
705            (Self::Tuple(_), _) => false,
706            (Self::Variant(ln, lv), Self::Variant(rn, rv)) => ln == rn && lv == rv,
707            (Self::Variant(..), _) => false,
708            (Self::Enum(l), Self::Enum(r)) => l == r,
709            (Self::Enum(_), _) => false,
710            (Self::Option(l), Self::Option(r)) => l == r,
711            (Self::Option(_), _) => false,
712            (Self::Result(l), Self::Result(r)) => l == r,
713            (Self::Result(_), _) => false,
714            (Self::Flags(l), Self::Flags(r)) => l == r,
715            (Self::Flags(_), _) => false,
716            (Self::Resource(l), Self::Resource(r)) => l == r,
717            (Self::Resource(_), _) => false,
718        }
719    }
720}
721
722impl Eq for Val {}
723
724struct GenericVariant<'a> {
725    discriminant: u32,
726    payload: Option<(&'a Val, InterfaceType)>,
727    abi: &'a CanonicalAbiInfo,
728    info: &'a VariantInfo,
729}
730
731impl GenericVariant<'_> {
732    fn result<'a>(
733        ty: &'a TypeResult,
734        r: &'a Result<Option<Box<Val>>, Option<Box<Val>>>,
735    ) -> Result<GenericVariant<'a>> {
736        let (discriminant, payload) = match r {
737            Ok(val) => {
738                let payload = match (val, ty.ok) {
739                    (Some(val), Some(ty)) => Some((&**val, ty)),
740                    (None, None) => None,
741                    (Some(_), None) => {
742                        bail!("payload provided to `ok` but not expected");
743                    }
744                    (None, Some(_)) => {
745                        bail!("payload expected to `ok` but not provided");
746                    }
747                };
748                (0, payload)
749            }
750            Err(val) => {
751                let payload = match (val, ty.err) {
752                    (Some(val), Some(ty)) => Some((&**val, ty)),
753                    (None, None) => None,
754                    (Some(_), None) => {
755                        bail!("payload provided to `err` but not expected");
756                    }
757                    (None, Some(_)) => {
758                        bail!("payload expected to `err` but not provided");
759                    }
760                };
761                (1, payload)
762            }
763        };
764        Ok(GenericVariant {
765            discriminant,
766            payload,
767            abi: &ty.abi,
768            info: &ty.info,
769        })
770    }
771
772    fn option<'a>(ty: &'a TypeOption, r: &'a Option<Box<Val>>) -> GenericVariant<'a> {
773        let (discriminant, payload) = match r {
774            None => (0, None),
775            Some(val) => (1, Some((&**val, ty.ty))),
776        };
777        GenericVariant {
778            discriminant,
779            payload,
780            abi: &ty.abi,
781            info: &ty.info,
782        }
783    }
784
785    fn enum_<'a>(ty: &'a TypeEnum, discriminant: &str) -> Result<GenericVariant<'a>> {
786        let discriminant = get_enum_discriminant(ty, discriminant)?;
787
788        Ok(GenericVariant {
789            discriminant,
790            payload: None,
791            abi: &ty.abi,
792            info: &ty.info,
793        })
794    }
795
796    fn variant<'a>(
797        ty: &'a TypeVariant,
798        discriminant_name: &str,
799        payload: &'a Option<Box<Val>>,
800    ) -> Result<GenericVariant<'a>> {
801        let (discriminant, payload_ty) = get_variant_discriminant(ty, discriminant_name)?;
802
803        let payload = match (payload, payload_ty) {
804            (Some(val), Some(ty)) => Some((&**val, *ty)),
805            (None, None) => None,
806            (Some(_), None) => bail!("did not expect a payload for case `{discriminant_name}`"),
807            (None, Some(_)) => bail!("expected a payload for case `{discriminant_name}`"),
808        };
809
810        Ok(GenericVariant {
811            discriminant,
812            payload,
813            abi: &ty.abi,
814            info: &ty.info,
815        })
816    }
817
818    fn lower<T>(
819        &self,
820        cx: &mut LowerContext<'_, T>,
821        dst: &mut IterMut<'_, MaybeUninit<ValRaw>>,
822    ) -> Result<()> {
823        next_mut(dst).write(ValRaw::u32(self.discriminant));
824
825        // For the remaining lowered representation of this variant that
826        // the payload didn't write we write out zeros here to ensure
827        // the entire variant is written.
828        let value_flat = match self.payload {
829            Some((value, ty)) => {
830                value.lower(cx, ty, dst)?;
831                cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap()
832            }
833            None => 0,
834        };
835        let variant_flat = self.abi.flat_count(usize::MAX).unwrap();
836        for _ in (1 + value_flat)..variant_flat {
837            next_mut(dst).write(ValRaw::u64(0));
838        }
839        Ok(())
840    }
841
842    fn store<T>(&self, cx: &mut LowerContext<'_, T>, offset: usize) -> Result<()> {
843        match self.info.size {
844            DiscriminantSize::Size1 => u8::try_from(self.discriminant)
845                .unwrap()
846                .linear_lower_to_memory(cx, InterfaceType::U8, offset)?,
847            DiscriminantSize::Size2 => u16::try_from(self.discriminant)
848                .unwrap()
849                .linear_lower_to_memory(cx, InterfaceType::U16, offset)?,
850            DiscriminantSize::Size4 => {
851                self.discriminant
852                    .linear_lower_to_memory(cx, InterfaceType::U32, offset)?
853            }
854        }
855
856        if let Some((value, ty)) = self.payload {
857            let offset = offset + usize::try_from(self.info.payload_offset32).unwrap();
858            value.store(cx, ty, offset)?;
859        }
860
861        Ok(())
862    }
863}
864
865fn load_list(cx: &mut LiftContext<'_>, ty: TypeListIndex, ptr: usize, len: usize) -> Result<Val> {
866    let elem = cx.types[ty].element;
867    let abi = cx.types.canonical_abi(&elem);
868    let element_size = usize::try_from(abi.size32).unwrap();
869    let element_alignment = abi.align32;
870
871    match len
872        .checked_mul(element_size)
873        .and_then(|len| ptr.checked_add(len))
874    {
875        Some(n) if n <= cx.memory().len() => {}
876        _ => bail!("list pointer/length out of bounds of memory"),
877    }
878    if ptr % usize::try_from(element_alignment)? != 0 {
879        bail!("list pointer is not aligned")
880    }
881
882    Ok(Val::List(
883        (0..len)
884            .map(|index| {
885                Val::load(
886                    cx,
887                    elem,
888                    &cx.memory()[ptr + (index * element_size)..][..element_size],
889                )
890            })
891            .collect::<Result<_>>()?,
892    ))
893}
894
895fn load_variant(
896    cx: &mut LiftContext<'_>,
897    info: &VariantInfo,
898    mut types: impl ExactSizeIterator<Item = Option<InterfaceType>>,
899    bytes: &[u8],
900) -> Result<(u32, Option<Box<Val>>)> {
901    let discriminant = match info.size {
902        DiscriminantSize::Size1 => u32::from(u8::linear_lift_from_memory(
903            cx,
904            InterfaceType::U8,
905            &bytes[..1],
906        )?),
907        DiscriminantSize::Size2 => u32::from(u16::linear_lift_from_memory(
908            cx,
909            InterfaceType::U16,
910            &bytes[..2],
911        )?),
912        DiscriminantSize::Size4 => {
913            u32::linear_lift_from_memory(cx, InterfaceType::U32, &bytes[..4])?
914        }
915    };
916    let case_ty = types.nth(discriminant as usize).ok_or_else(|| {
917        anyhow!(
918            "discriminant {} out of range [0..{})",
919            discriminant,
920            types.len()
921        )
922    })?;
923    let value = match case_ty {
924        Some(case_ty) => {
925            let payload_offset = usize::try_from(info.payload_offset32).unwrap();
926            let case_abi = cx.types.canonical_abi(&case_ty);
927            let case_size = usize::try_from(case_abi.size32).unwrap();
928            Some(Box::new(Val::load(
929                cx,
930                case_ty,
931                &bytes[payload_offset..][..case_size],
932            )?))
933        }
934        None => None,
935    };
936    Ok((discriminant, value))
937}
938
939fn lift_variant(
940    cx: &mut LiftContext<'_>,
941    flatten_count: usize,
942    mut types: impl ExactSizeIterator<Item = Option<InterfaceType>>,
943    src: &mut Iter<'_, ValRaw>,
944) -> Result<(u32, Option<Box<Val>>)> {
945    let len = types.len();
946    let discriminant = next(src).get_u32();
947    let ty = types
948        .nth(discriminant as usize)
949        .ok_or_else(|| anyhow!("discriminant {} out of range [0..{})", discriminant, len))?;
950    let (value, value_flat) = match ty {
951        Some(ty) => (
952            Some(Box::new(Val::lift(cx, ty, src)?)),
953            cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
954        ),
955        None => (None, 0),
956    };
957    for _ in (1 + value_flat)..flatten_count {
958        next(src);
959    }
960    Ok((discriminant, value))
961}
962
963/// Lower a list with the specified element type and values.
964fn lower_list<T>(
965    cx: &mut LowerContext<'_, T>,
966    element_type: InterfaceType,
967    items: &[Val],
968) -> Result<(usize, usize)> {
969    let abi = cx.types.canonical_abi(&element_type);
970    let elt_size = usize::try_from(abi.size32)?;
971    let elt_align = abi.align32;
972    let size = items
973        .len()
974        .checked_mul(elt_size)
975        .ok_or_else(|| anyhow::anyhow!("size overflow copying a list"))?;
976    let ptr = cx.realloc(0, 0, elt_align, size)?;
977    let mut element_ptr = ptr;
978    for item in items {
979        item.store(cx, element_type, element_ptr)?;
980        element_ptr += elt_size;
981    }
982    Ok((ptr, items.len()))
983}
984
985fn push_flags(ty: &TypeFlags, flags: &mut Vec<String>, mut offset: u32, mut bits: u32) {
986    while bits > 0 {
987        if bits & 1 != 0 {
988            flags.push(ty.names[offset as usize].clone());
989        }
990        bits >>= 1;
991        offset += 1;
992    }
993}
994
995fn flags_to_storage(ty: &TypeFlags, flags: &[String]) -> Result<Vec<u32>> {
996    let mut storage = match FlagsSize::from_count(ty.names.len()) {
997        FlagsSize::Size0 => Vec::new(),
998        FlagsSize::Size1 | FlagsSize::Size2 => vec![0],
999        FlagsSize::Size4Plus(n) => vec![0; n.into()],
1000    };
1001
1002    for flag in flags {
1003        let bit = ty
1004            .names
1005            .get_index_of(flag)
1006            .ok_or_else(|| anyhow::anyhow!("unknown flag: `{flag}`"))?;
1007        storage[bit / 32] |= 1 << (bit % 32);
1008    }
1009    Ok(storage)
1010}
1011
1012fn get_enum_discriminant(ty: &TypeEnum, n: &str) -> Result<u32> {
1013    ty.names
1014        .get_index_of(n)
1015        .ok_or_else(|| anyhow::anyhow!("enum variant name `{n}` is not valid"))
1016        .map(|i| i.try_into().unwrap())
1017}
1018
1019fn get_variant_discriminant<'a>(
1020    ty: &'a TypeVariant,
1021    name: &str,
1022) -> Result<(u32, &'a Option<InterfaceType>)> {
1023    let (i, _, ty) = ty
1024        .cases
1025        .get_full(name)
1026        .ok_or_else(|| anyhow::anyhow!("unknown variant case: `{name}`"))?;
1027    Ok((i.try_into().unwrap(), ty))
1028}
1029
1030fn next<'a>(src: &mut Iter<'a, ValRaw>) -> &'a ValRaw {
1031    src.next().unwrap()
1032}
1033
1034fn next_mut<'a>(dst: &mut IterMut<'a, MaybeUninit<ValRaw>>) -> &'a mut MaybeUninit<ValRaw> {
1035    dst.next().unwrap()
1036}
1037
1038#[cold]
1039fn unexpected<T>(ty: InterfaceType, val: &Val) -> Result<T> {
1040    bail!(
1041        "type mismatch: expected {}, found {}",
1042        desc(&ty),
1043        val.desc()
1044    )
1045}