wasmtime/runtime/component/
values.rs

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