dusk_wasmtime/runtime/component/
values.rs

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