Skip to main content

wasmtime/runtime/component/
values.rs

1use crate::ValRaw;
2use crate::component::ResourceAny;
3use crate::component::concurrent::{self, ErrorContext, FutureAny, StreamAny};
4use crate::component::func::{Lift, LiftContext, Lower, LowerContext, desc};
5use crate::prelude::*;
6use core::mem::MaybeUninit;
7use core::slice::{Iter, IterMut};
8use wasmtime_component_util::{DiscriminantSize, FlagsSize};
9use wasmtime_environ::component::{
10    CanonicalAbiInfo, InterfaceType, TypeEnum, TypeFlags, TypeListIndex, TypeMap, TypeMapIndex,
11    TypeOption, TypeResult, TypeVariant, VariantInfo,
12};
13
14/// Represents possible runtime values which a component function can either
15/// consume or produce
16///
17/// This is a dynamic representation of possible values in the component model.
18/// Note that this is not an efficient representation but is instead intended to
19/// be a flexible and somewhat convenient representation. The most efficient
20/// representation of component model types is to use the `bindgen!` macro to
21/// generate native Rust types with specialized liftings and lowerings.
22///
23/// This type is used in conjunction with [`Func::call`] for example if the
24/// signature of a component is not statically known ahead of time.
25///
26/// # Equality and `Val`
27///
28/// This type implements both the Rust `PartialEq` and `Eq` traits. This type
29/// additionally contains values which are not necessarily easily equated,
30/// however, such as floats (`Float32` and `Float64`), resources, and maps.
31/// Equality does require that two values have the same type, and then these
32/// cases are handled as:
33///
34/// * Floats are tested if they are "semantically the same" meaning all NaN
35///   values are equal to all other NaN values. Additionally zero values must be
36///   exactly the same, so positive zero is not equal to negative zero. The
37///   primary use case at this time is fuzzing-related equality which this is
38///   sufficient for.
39///
40/// * Resources are tested if their types and indices into the host table are
41///   equal. This does not compare the underlying representation so borrows of
42///   the same guest resource are not considered equal. This additionally
43///   doesn't go further and test for equality in the guest itself (for example
44///   two different heap allocations of `Box<u32>` can be equal in normal Rust
45///   if they contain the same value, but will never be considered equal when
46///   compared as `Val::Resource`s).
47///
48/// * Maps are compared entry-by-entry in order, so the same logical map with
49///   entries in a different order, or with duplicate keys, compares unequal.
50///
51/// In general if a strict guarantee about equality is required here it's
52/// recommended to "build your own" as this equality intended for fuzzing
53/// Wasmtime may not be suitable for you.
54///
55/// # Component model types and `Val`
56///
57/// The `Val` type here does not contain enough information to say what the
58/// component model type of a `Val` is. This is instead more of an AST of sorts.
59/// For example the `Val::Enum` only carries information about a single
60/// discriminant, not the entire enumeration or what it's a discriminant of.
61///
62/// This means that when a `Val` is passed to Wasmtime, for example as a
63/// function parameter when calling a function or as a return value from an
64/// host-defined imported function, then it must pass a type-check. Instances of
65/// `Val` are type-checked against what's required by the component itself.
66///
67/// [`Func::call`]: crate::component::Func::call
68///
69/// # Ownership and handles
70///
71/// This type can contain handles to resources owned within a store, such as the
72/// `Resource`, `Future`, and `Stream` variants. For all of these variants it's
73/// required that when this `Val` is dropped that the corresponding resource in
74/// the store is additionally dropped, lest the handle is leaked within the
75/// store. This means that if you're receiving `Val`s you will need to be quite
76/// careful when dropping them or letting them go out of scope to handle this
77/// issue if it's applicable to your use case.
78#[derive(Debug, Clone)]
79#[expect(missing_docs, reason = "self-describing variants")]
80pub enum Val {
81    Bool(bool),
82    S8(i8),
83    U8(u8),
84    S16(i16),
85    U16(u16),
86    S32(i32),
87    U32(u32),
88    S64(i64),
89    U64(u64),
90    Float32(f32),
91    Float64(f64),
92    Char(char),
93    String(String),
94    List(Vec<Val>),
95    /// A map type represented as a list of key-value pairs.
96    ///
97    /// Entries are kept exactly as they appear in the canonical ABI list, in
98    /// order and including duplicate keys. Per the component model, the last
99    /// entry for a key is the one that defines its value when the list is
100    /// interpreted as a map.
101    Map(Vec<(Val, Val)>),
102    Record(Vec<(String, Val)>),
103    Tuple(Vec<Val>),
104    Variant(String, Option<Box<Val>>),
105    Enum(String),
106    Option(Option<Box<Val>>),
107    Result(Result<Option<Box<Val>>, Option<Box<Val>>>),
108    Flags(Vec<String>),
109    Resource(ResourceAny),
110    Future(FutureAny),
111    Stream(StreamAny),
112    ErrorContext(ErrorContextAny),
113    FixedLengthList(Vec<Val>),
114}
115
116impl Val {
117    /// Deserialize a value of this type from core Wasm stack values.
118    pub(crate) fn lift(
119        cx: &mut LiftContext<'_>,
120        ty: InterfaceType,
121        src: &mut Iter<'_, ValRaw>,
122    ) -> Result<Val> {
123        Ok(match ty {
124            InterfaceType::Bool => Val::Bool(bool::linear_lift_from_flat(cx, ty, next(src))?),
125            InterfaceType::S8 => Val::S8(i8::linear_lift_from_flat(cx, ty, next(src))?),
126            InterfaceType::U8 => Val::U8(u8::linear_lift_from_flat(cx, ty, next(src))?),
127            InterfaceType::S16 => Val::S16(i16::linear_lift_from_flat(cx, ty, next(src))?),
128            InterfaceType::U16 => Val::U16(u16::linear_lift_from_flat(cx, ty, next(src))?),
129            InterfaceType::S32 => Val::S32(i32::linear_lift_from_flat(cx, ty, next(src))?),
130            InterfaceType::U32 => Val::U32(u32::linear_lift_from_flat(cx, ty, next(src))?),
131            InterfaceType::S64 => Val::S64(i64::linear_lift_from_flat(cx, ty, next(src))?),
132            InterfaceType::U64 => Val::U64(u64::linear_lift_from_flat(cx, ty, next(src))?),
133            InterfaceType::Float32 => Val::Float32(f32::linear_lift_from_flat(cx, ty, next(src))?),
134            InterfaceType::Float64 => Val::Float64(f64::linear_lift_from_flat(cx, ty, next(src))?),
135            InterfaceType::Char => Val::Char(char::linear_lift_from_flat(cx, ty, next(src))?),
136            InterfaceType::Own(_) | InterfaceType::Borrow(_) => {
137                Val::Resource(ResourceAny::linear_lift_from_flat(cx, ty, next(src))?)
138            }
139            InterfaceType::String => Val::String(<_>::linear_lift_from_flat(
140                cx,
141                ty,
142                &[*next(src), *next(src)],
143            )?),
144            InterfaceType::List(i) => {
145                let (ptr, len) = lift_flat_pointer_pair(cx, src)?;
146                load_list(cx, i, ptr, len)?
147            }
148            InterfaceType::Map(i) => {
149                let (ptr, len) = lift_flat_pointer_pair(cx, src)?;
150                load_map(cx, i, ptr, len)?
151            }
152            InterfaceType::Record(i) => {
153                let fields = &cx.types[i].fields;
154                cx.consume_fuel_array(fields.len(), size_of::<Val>())?;
155                Val::Record(
156                    fields
157                        .iter()
158                        .map(|field| {
159                            let val = Self::lift(cx, field.ty, src)?;
160                            cx.consume_fuel(field.name.len())?;
161                            Ok((field.name.to_string(), val))
162                        })
163                        .collect::<Result<_>>()?,
164                )
165            }
166            InterfaceType::Tuple(i) => {
167                let types = &cx.types[i].types;
168                cx.consume_fuel_array(types.len(), size_of::<Val>())?;
169                Val::Tuple(
170                    types
171                        .iter()
172                        .map(|ty| Self::lift(cx, *ty, src))
173                        .collect::<Result<_>>()?,
174                )
175            }
176            InterfaceType::Variant(i) => {
177                let vty = &cx.types[i];
178                let (discriminant, value) = lift_variant(
179                    cx,
180                    cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
181                    vty.cases.values().copied(),
182                    src,
183                )?;
184
185                let (k, _) = vty.cases.get_index(discriminant as usize).unwrap();
186                cx.consume_fuel(k.len())?;
187                Val::Variant(k.to_string(), value)
188            }
189            InterfaceType::Enum(i) => {
190                let ety = &cx.types[i];
191                let (discriminant, _) = lift_variant(
192                    cx,
193                    cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
194                    ety.names.iter().map(|_| None),
195                    src,
196                )?;
197
198                let name = &ety.names[discriminant as usize];
199                cx.consume_fuel(name.len())?;
200                Val::Enum(name.to_string())
201            }
202            InterfaceType::Option(i) => {
203                let (_discriminant, value) = lift_variant(
204                    cx,
205                    cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
206                    [None, Some(cx.types[i].ty)].into_iter(),
207                    src,
208                )?;
209
210                Val::Option(value)
211            }
212            InterfaceType::Result(i) => {
213                let result_ty = &cx.types[i];
214                let (discriminant, value) = lift_variant(
215                    cx,
216                    cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
217                    [result_ty.ok, result_ty.err].into_iter(),
218                    src,
219                )?;
220
221                Val::Result(if discriminant == 0 {
222                    Ok(value)
223                } else {
224                    Err(value)
225                })
226            }
227            InterfaceType::Flags(i) => {
228                let u32_count = cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap();
229                let ty = &cx.types[i];
230                let mut flags = Vec::new();
231                for i in 0..u32::try_from(u32_count).unwrap() {
232                    let bits = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))?;
233                    push_flags(cx, ty, &mut flags, i * 32, bits)?;
234                }
235
236                Val::Flags(flags)
237            }
238            InterfaceType::Future(_) => {
239                Val::Future(FutureAny::linear_lift_from_flat(cx, ty, next(src))?)
240            }
241            InterfaceType::Stream(_) => {
242                Val::Stream(StreamAny::linear_lift_from_flat(cx, ty, next(src))?)
243            }
244            InterfaceType::ErrorContext(_) => {
245                ErrorContext::linear_lift_from_flat(cx, ty, next(src))?.into_val()
246            }
247            InterfaceType::FixedLengthList(i) => {
248                let number_elements = usize::try_from(cx.types[i].size)?;
249                cx.consume_fuel_array(number_elements, size_of::<Val>())?;
250                Val::FixedLengthList(
251                    (0..number_elements)
252                        .map(|_| Self::lift(cx, cx.types[i].element, src))
253                        .collect::<Result<_>>()?,
254                )
255            }
256        })
257    }
258
259    /// Deserialize a value of this type from the heap.
260    pub(crate) fn load(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Val> {
261        Ok(match ty {
262            InterfaceType::Bool => Val::Bool(bool::linear_lift_from_memory(cx, ty, bytes)?),
263            InterfaceType::S8 => Val::S8(i8::linear_lift_from_memory(cx, ty, bytes)?),
264            InterfaceType::U8 => Val::U8(u8::linear_lift_from_memory(cx, ty, bytes)?),
265            InterfaceType::S16 => Val::S16(i16::linear_lift_from_memory(cx, ty, bytes)?),
266            InterfaceType::U16 => Val::U16(u16::linear_lift_from_memory(cx, ty, bytes)?),
267            InterfaceType::S32 => Val::S32(i32::linear_lift_from_memory(cx, ty, bytes)?),
268            InterfaceType::U32 => Val::U32(u32::linear_lift_from_memory(cx, ty, bytes)?),
269            InterfaceType::S64 => Val::S64(i64::linear_lift_from_memory(cx, ty, bytes)?),
270            InterfaceType::U64 => Val::U64(u64::linear_lift_from_memory(cx, ty, bytes)?),
271            InterfaceType::Float32 => Val::Float32(f32::linear_lift_from_memory(cx, ty, bytes)?),
272            InterfaceType::Float64 => Val::Float64(f64::linear_lift_from_memory(cx, ty, bytes)?),
273            InterfaceType::Char => Val::Char(char::linear_lift_from_memory(cx, ty, bytes)?),
274            InterfaceType::String => Val::String(<_>::linear_lift_from_memory(cx, ty, bytes)?),
275            InterfaceType::Own(_) | InterfaceType::Borrow(_) => {
276                Val::Resource(ResourceAny::linear_lift_from_memory(cx, ty, bytes)?)
277            }
278            InterfaceType::List(i) => {
279                let (ptr, len) = load_flat_pointer_pair(bytes);
280                load_list(cx, i, ptr, len)?
281            }
282            InterfaceType::Map(i) => {
283                let (ptr, len) = load_flat_pointer_pair(bytes);
284                load_map(cx, i, ptr, len)?
285            }
286
287            InterfaceType::Record(i) => {
288                let mut offset = 0;
289                let fields = cx.types[i].fields.iter();
290                cx.consume_fuel_array(fields.len(), size_of::<Val>())?;
291                Val::Record(
292                    fields
293                        .map(|field| -> Result<(String, Val)> {
294                            cx.consume_fuel(field.name.len())?;
295                            let abi = cx.types.canonical_abi(&field.ty);
296                            let offset = abi.next_field32(&mut offset);
297                            let offset = usize::try_from(offset).unwrap();
298                            let size = usize::try_from(abi.size32).unwrap();
299                            Ok((
300                                field.name.to_string(),
301                                Val::load(cx, field.ty, &bytes[offset..][..size])?,
302                            ))
303                        })
304                        .collect::<Result<_>>()?,
305                )
306            }
307            InterfaceType::Tuple(i) => {
308                let types = cx.types[i].types.iter().copied();
309                cx.consume_fuel_array(types.len(), size_of::<Val>())?;
310                let mut offset = 0;
311                Val::Tuple(
312                    types
313                        .map(|ty| {
314                            let abi = cx.types.canonical_abi(&ty);
315                            let offset = abi.next_field32(&mut offset);
316                            let offset = usize::try_from(offset).unwrap();
317                            let size = usize::try_from(abi.size32).unwrap();
318                            Val::load(cx, ty, &bytes[offset..][..size])
319                        })
320                        .collect::<Result<_>>()?,
321                )
322            }
323            InterfaceType::Variant(i) => {
324                let ty = &cx.types[i];
325                let (discriminant, value) =
326                    load_variant(cx, &ty.info, ty.cases.values().copied(), bytes)?;
327
328                let (k, _) = ty.cases.get_index(discriminant as usize).unwrap();
329                cx.consume_fuel(k.len())?;
330                Val::Variant(k.to_string(), value)
331            }
332            InterfaceType::Enum(i) => {
333                let ty = &cx.types[i];
334                let (discriminant, _) =
335                    load_variant(cx, &ty.info, ty.names.iter().map(|_| None), bytes)?;
336
337                let name = &ty.names[discriminant as usize];
338                cx.consume_fuel(name.len())?;
339                Val::Enum(name.to_string())
340            }
341            InterfaceType::Option(i) => {
342                let ty = &cx.types[i];
343                let (_discriminant, value) =
344                    load_variant(cx, &ty.info, [None, Some(ty.ty)].into_iter(), bytes)?;
345
346                Val::Option(value)
347            }
348            InterfaceType::Result(i) => {
349                let ty = &cx.types[i];
350                let (discriminant, value) =
351                    load_variant(cx, &ty.info, [ty.ok, ty.err].into_iter(), bytes)?;
352
353                Val::Result(if discriminant == 0 {
354                    Ok(value)
355                } else {
356                    Err(value)
357                })
358            }
359            InterfaceType::Flags(i) => {
360                let ty = &cx.types[i];
361                let mut flags = Vec::new();
362                match FlagsSize::from_count(ty.names.len()) {
363                    FlagsSize::Size0 => {}
364                    FlagsSize::Size1 => {
365                        let bits = u8::linear_lift_from_memory(cx, InterfaceType::U8, bytes)?;
366                        push_flags(cx, ty, &mut flags, 0, u32::from(bits))?;
367                    }
368                    FlagsSize::Size2 => {
369                        let bits = u16::linear_lift_from_memory(cx, InterfaceType::U16, bytes)?;
370                        push_flags(cx, ty, &mut flags, 0, u32::from(bits))?;
371                    }
372                    FlagsSize::Size4Plus(n) => {
373                        for i in 0..n {
374                            let bits = u32::linear_lift_from_memory(
375                                cx,
376                                InterfaceType::U32,
377                                &bytes[usize::from(i) * 4..][..4],
378                            )?;
379                            push_flags(cx, ty, &mut flags, u32::from(i) * 32, bits)?;
380                        }
381                    }
382                }
383                Val::Flags(flags)
384            }
385            InterfaceType::Future(_) => FutureAny::linear_lift_from_memory(cx, ty, bytes)?.into(),
386            InterfaceType::Stream(_) => StreamAny::linear_lift_from_memory(cx, ty, bytes)?.into(),
387            InterfaceType::ErrorContext(_) => {
388                ErrorContext::linear_lift_from_memory(cx, ty, bytes)?.into_val()
389            }
390            InterfaceType::FixedLengthList(i) => {
391                let element_type = cx.types[i].element;
392                let abi = cx.types.canonical_abi(&element_type);
393                let element_size = usize::try_from(abi.size32)?;
394                let number_elements = usize::try_from(cx.types[i].size)?;
395
396                match number_elements.checked_mul(element_size) {
397                    Some(total_size) if total_size <= bytes.len() => {
398                        cx.consume_fuel_array(number_elements, size_of::<Val>())?;
399                        Val::FixedLengthList(
400                            (0..number_elements)
401                                .map(|n| {
402                                    // the match already checked that the whole array fits into usize
403                                    let offset = element_size.wrapping_mul(n);
404                                    Val::load(cx, element_type, &bytes[offset..][..element_size])
405                                })
406                                .collect::<Result<_>>()?,
407                        )
408                    }
409                    _ => bail!("fixed length list out of bounds of memory"),
410                }
411            }
412        })
413    }
414
415    /// Serialize this value as core Wasm stack values.
416    pub(crate) fn lower<T>(
417        &self,
418        cx: &mut LowerContext<'_, T>,
419        ty: InterfaceType,
420        dst: &mut IterMut<'_, MaybeUninit<ValRaw>>,
421    ) -> Result<()> {
422        match (ty, self) {
423            (InterfaceType::Bool, Val::Bool(value)) => {
424                value.linear_lower_to_flat(cx, ty, next_mut(dst))
425            }
426            (InterfaceType::Bool, _) => unexpected(ty, self),
427            (InterfaceType::S8, Val::S8(value)) => {
428                value.linear_lower_to_flat(cx, ty, next_mut(dst))
429            }
430            (InterfaceType::S8, _) => unexpected(ty, self),
431            (InterfaceType::U8, Val::U8(value)) => {
432                value.linear_lower_to_flat(cx, ty, next_mut(dst))
433            }
434            (InterfaceType::U8, _) => unexpected(ty, self),
435            (InterfaceType::S16, Val::S16(value)) => {
436                value.linear_lower_to_flat(cx, ty, next_mut(dst))
437            }
438            (InterfaceType::S16, _) => unexpected(ty, self),
439            (InterfaceType::U16, Val::U16(value)) => {
440                value.linear_lower_to_flat(cx, ty, next_mut(dst))
441            }
442            (InterfaceType::U16, _) => unexpected(ty, self),
443            (InterfaceType::S32, Val::S32(value)) => {
444                value.linear_lower_to_flat(cx, ty, next_mut(dst))
445            }
446            (InterfaceType::S32, _) => unexpected(ty, self),
447            (InterfaceType::U32, Val::U32(value)) => {
448                value.linear_lower_to_flat(cx, ty, next_mut(dst))
449            }
450            (InterfaceType::U32, _) => unexpected(ty, self),
451            (InterfaceType::S64, Val::S64(value)) => {
452                value.linear_lower_to_flat(cx, ty, next_mut(dst))
453            }
454            (InterfaceType::S64, _) => unexpected(ty, self),
455            (InterfaceType::U64, Val::U64(value)) => {
456                value.linear_lower_to_flat(cx, ty, next_mut(dst))
457            }
458            (InterfaceType::U64, _) => unexpected(ty, self),
459            (InterfaceType::Float32, Val::Float32(value)) => {
460                value.linear_lower_to_flat(cx, ty, next_mut(dst))
461            }
462            (InterfaceType::Float32, _) => unexpected(ty, self),
463            (InterfaceType::Float64, Val::Float64(value)) => {
464                value.linear_lower_to_flat(cx, ty, next_mut(dst))
465            }
466            (InterfaceType::Float64, _) => unexpected(ty, self),
467            (InterfaceType::Char, Val::Char(value)) => {
468                value.linear_lower_to_flat(cx, ty, next_mut(dst))
469            }
470            (InterfaceType::Char, _) => unexpected(ty, self),
471            // NB: `lower` on `ResourceAny` does its own type-checking, so skip
472            // looking at it here.
473            (InterfaceType::Borrow(_) | InterfaceType::Own(_), Val::Resource(value)) => {
474                value.linear_lower_to_flat(cx, ty, next_mut(dst))
475            }
476            (InterfaceType::Borrow(_) | InterfaceType::Own(_), _) => unexpected(ty, self),
477            (InterfaceType::String, Val::String(value)) => {
478                let my_dst = &mut MaybeUninit::<[ValRaw; 2]>::uninit();
479                value.linear_lower_to_flat(cx, ty, my_dst)?;
480                let my_dst = unsafe { my_dst.assume_init() };
481                next_mut(dst).write(my_dst[0]);
482                next_mut(dst).write(my_dst[1]);
483                Ok(())
484            }
485            (InterfaceType::String, _) => 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                next_mut(dst).write(ValRaw::i64(ptr as i64));
490                next_mut(dst).write(ValRaw::i64(len as i64));
491                Ok(())
492            }
493            (InterfaceType::List(_), _) => unexpected(ty, self),
494            (InterfaceType::Map(ty), Val::Map(pairs)) => {
495                let map_ty = &cx.types[ty];
496                let (ptr, len) = lower_map(cx, map_ty, pairs)?;
497                next_mut(dst).write(ValRaw::i64(ptr as i64));
498                next_mut(dst).write(ValRaw::i64(len as i64));
499                Ok(())
500            }
501            (InterfaceType::Map(_), _) => unexpected(ty, self),
502            (InterfaceType::Record(ty), Val::Record(values)) => {
503                let ty = &cx.types[ty];
504                if ty.fields.len() != values.len() {
505                    bail!("expected {} fields, got {}", ty.fields.len(), values.len());
506                }
507                for ((name, value), field) in values.iter().zip(ty.fields.iter()) {
508                    if **name != *field.name {
509                        bail!("expected field `{}`, got `{name}`", field.name);
510                    }
511                    value.lower(cx, field.ty, dst)?;
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                for (value, ty) in values.iter().zip(ty.types.iter()) {
522                    value.lower(cx, *ty, dst)?;
523                }
524                Ok(())
525            }
526            (InterfaceType::Tuple(_), _) => unexpected(ty, self),
527            (InterfaceType::Variant(ty), Val::Variant(n, v)) => {
528                GenericVariant::variant(&cx.types[ty], n, v)?.lower(cx, dst)
529            }
530            (InterfaceType::Variant(_), _) => unexpected(ty, self),
531            (InterfaceType::Option(ty), Val::Option(v)) => {
532                GenericVariant::option(&cx.types[ty], v).lower(cx, dst)
533            }
534            (InterfaceType::Option(_), _) => unexpected(ty, self),
535            (InterfaceType::Result(ty), Val::Result(v)) => {
536                GenericVariant::result(&cx.types[ty], v)?.lower(cx, dst)
537            }
538            (InterfaceType::Result(_), _) => unexpected(ty, self),
539            (InterfaceType::Enum(ty), Val::Enum(discriminant)) => {
540                let discriminant = get_enum_discriminant(&cx.types[ty], discriminant)?;
541                next_mut(dst).write(ValRaw::u32(discriminant));
542                Ok(())
543            }
544            (InterfaceType::Enum(_), _) => unexpected(ty, self),
545            (InterfaceType::Flags(ty), Val::Flags(value)) => {
546                let ty = &cx.types[ty];
547                let storage = flags_to_storage(ty, value)?;
548                for value in storage {
549                    next_mut(dst).write(ValRaw::u32(value));
550                }
551                Ok(())
552            }
553            (InterfaceType::Flags(_), _) => unexpected(ty, self),
554            (InterfaceType::Future(_), Val::Future(f)) => {
555                f.linear_lower_to_flat(cx, ty, next_mut(dst))
556            }
557            (InterfaceType::Future(_), _) => unexpected(ty, self),
558            (InterfaceType::Stream(_), Val::Stream(s)) => {
559                s.linear_lower_to_flat(cx, ty, next_mut(dst))
560            }
561            (InterfaceType::Stream(_), _) => unexpected(ty, self),
562            (InterfaceType::ErrorContext(_), Val::ErrorContext(ErrorContextAny(rep))) => {
563                concurrent::lower_error_context_to_index(*rep, cx, ty)?.linear_lower_to_flat(
564                    cx,
565                    InterfaceType::U32,
566                    next_mut(dst),
567                )
568            }
569            (InterfaceType::ErrorContext(_), _) => unexpected(ty, self),
570            (InterfaceType::FixedLengthList(ty), Val::FixedLengthList(values)) => {
571                let ty = &cx.types[ty];
572                if ty.size as usize != values.len() {
573                    bail!("expected vec of size {}, got {}", ty.size, values.len());
574                }
575                for value in values {
576                    value.lower(cx, ty.element, dst)?;
577                }
578                Ok(())
579            }
580            (InterfaceType::FixedLengthList(_), _) => unexpected(ty, self),
581        }
582    }
583
584    /// Serialize this value to the heap at the specified memory location.
585    pub(crate) fn store<T>(
586        &self,
587        cx: &mut LowerContext<'_, T>,
588        ty: InterfaceType,
589        offset: usize,
590    ) -> Result<()> {
591        debug_assert!(offset % usize::try_from(cx.types.canonical_abi(&ty).align32)? == 0);
592
593        match (ty, self) {
594            (InterfaceType::Bool, Val::Bool(value)) => value.linear_lower_to_memory(cx, ty, offset),
595            (InterfaceType::Bool, _) => unexpected(ty, self),
596            (InterfaceType::U8, Val::U8(value)) => value.linear_lower_to_memory(cx, ty, offset),
597            (InterfaceType::U8, _) => unexpected(ty, self),
598            (InterfaceType::S8, Val::S8(value)) => value.linear_lower_to_memory(cx, ty, offset),
599            (InterfaceType::S8, _) => unexpected(ty, self),
600            (InterfaceType::U16, Val::U16(value)) => value.linear_lower_to_memory(cx, ty, offset),
601            (InterfaceType::U16, _) => unexpected(ty, self),
602            (InterfaceType::S16, Val::S16(value)) => value.linear_lower_to_memory(cx, ty, offset),
603            (InterfaceType::S16, _) => unexpected(ty, self),
604            (InterfaceType::U32, Val::U32(value)) => value.linear_lower_to_memory(cx, ty, offset),
605            (InterfaceType::U32, _) => unexpected(ty, self),
606            (InterfaceType::S32, Val::S32(value)) => value.linear_lower_to_memory(cx, ty, offset),
607            (InterfaceType::S32, _) => unexpected(ty, self),
608            (InterfaceType::U64, Val::U64(value)) => value.linear_lower_to_memory(cx, ty, offset),
609            (InterfaceType::U64, _) => unexpected(ty, self),
610            (InterfaceType::S64, Val::S64(value)) => value.linear_lower_to_memory(cx, ty, offset),
611            (InterfaceType::S64, _) => unexpected(ty, self),
612            (InterfaceType::Float32, Val::Float32(value)) => {
613                value.linear_lower_to_memory(cx, ty, offset)
614            }
615            (InterfaceType::Float32, _) => unexpected(ty, self),
616            (InterfaceType::Float64, Val::Float64(value)) => {
617                value.linear_lower_to_memory(cx, ty, offset)
618            }
619            (InterfaceType::Float64, _) => unexpected(ty, self),
620            (InterfaceType::Char, Val::Char(value)) => value.linear_lower_to_memory(cx, ty, offset),
621            (InterfaceType::Char, _) => unexpected(ty, self),
622            (InterfaceType::String, Val::String(value)) => {
623                value.linear_lower_to_memory(cx, ty, offset)
624            }
625            (InterfaceType::String, _) => unexpected(ty, self),
626
627            // NB: resources do type-checking when they lower.
628            (InterfaceType::Borrow(_) | InterfaceType::Own(_), Val::Resource(value)) => {
629                value.linear_lower_to_memory(cx, ty, offset)
630            }
631            (InterfaceType::Borrow(_) | InterfaceType::Own(_), _) => unexpected(ty, self),
632            (InterfaceType::List(ty), Val::List(values)) => {
633                let ty = &cx.types[ty];
634                let (ptr, len) = lower_list(cx, ty.element, values)?;
635                // FIXME(#4311): needs memory64 handling
636                *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes();
637                *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes();
638                Ok(())
639            }
640            (InterfaceType::List(_), _) => unexpected(ty, self),
641            (InterfaceType::Map(ty_idx), Val::Map(values)) => {
642                let map_ty = &cx.types[ty_idx];
643                let (ptr, len) = lower_map(cx, map_ty, values)?;
644                // FIXME(#4311): needs memory64 handling
645                *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes();
646                *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes();
647                Ok(())
648            }
649            (InterfaceType::Map(_), _) => unexpected(ty, self),
650            (InterfaceType::Record(ty), Val::Record(values)) => {
651                let ty = &cx.types[ty];
652                if ty.fields.len() != values.len() {
653                    bail!("expected {} fields, got {}", ty.fields.len(), values.len());
654                }
655                let mut offset = offset;
656                for ((name, value), field) in values.iter().zip(ty.fields.iter()) {
657                    if **name != *field.name {
658                        bail!("expected field `{}`, got `{name}`", field.name);
659                    }
660                    value.store(
661                        cx,
662                        field.ty,
663                        cx.types
664                            .canonical_abi(&field.ty)
665                            .next_field32_size(&mut offset),
666                    )?;
667                }
668                Ok(())
669            }
670            (InterfaceType::Record(_), _) => unexpected(ty, self),
671            (InterfaceType::Tuple(ty), Val::Tuple(values)) => {
672                let ty = &cx.types[ty];
673                if ty.types.len() != values.len() {
674                    bail!("expected {} types, got {}", ty.types.len(), values.len());
675                }
676                let mut offset = offset;
677                for (value, ty) in values.iter().zip(ty.types.iter()) {
678                    value.store(
679                        cx,
680                        *ty,
681                        cx.types.canonical_abi(ty).next_field32_size(&mut offset),
682                    )?;
683                }
684                Ok(())
685            }
686            (InterfaceType::Tuple(_), _) => unexpected(ty, self),
687
688            (InterfaceType::Variant(ty), Val::Variant(n, v)) => {
689                GenericVariant::variant(&cx.types[ty], n, v)?.store(cx, offset)
690            }
691            (InterfaceType::Variant(_), _) => unexpected(ty, self),
692            (InterfaceType::Enum(ty), Val::Enum(v)) => {
693                GenericVariant::enum_(&cx.types[ty], v)?.store(cx, offset)
694            }
695            (InterfaceType::Enum(_), _) => unexpected(ty, self),
696            (InterfaceType::Option(ty), Val::Option(v)) => {
697                GenericVariant::option(&cx.types[ty], v).store(cx, offset)
698            }
699            (InterfaceType::Option(_), _) => unexpected(ty, self),
700            (InterfaceType::Result(ty), Val::Result(v)) => {
701                GenericVariant::result(&cx.types[ty], v)?.store(cx, offset)
702            }
703            (InterfaceType::Result(_), _) => unexpected(ty, self),
704
705            (InterfaceType::Flags(ty), Val::Flags(flags)) => {
706                let ty = &cx.types[ty];
707                let storage = flags_to_storage(ty, flags)?;
708                match FlagsSize::from_count(ty.names.len()) {
709                    FlagsSize::Size0 => {}
710                    FlagsSize::Size1 => u8::try_from(storage[0]).unwrap().linear_lower_to_memory(
711                        cx,
712                        InterfaceType::U8,
713                        offset,
714                    )?,
715                    FlagsSize::Size2 => u16::try_from(storage[0]).unwrap().linear_lower_to_memory(
716                        cx,
717                        InterfaceType::U16,
718                        offset,
719                    )?,
720                    FlagsSize::Size4Plus(_) => {
721                        let mut offset = offset;
722                        for value in storage {
723                            value.linear_lower_to_memory(cx, InterfaceType::U32, offset)?;
724                            offset += 4;
725                        }
726                    }
727                }
728                Ok(())
729            }
730            (InterfaceType::Flags(_), _) => unexpected(ty, self),
731            (InterfaceType::Future(_), Val::Future(f)) => f.linear_lower_to_memory(cx, ty, offset),
732            (InterfaceType::Future(_), _) => unexpected(ty, self),
733            (InterfaceType::Stream(_), Val::Stream(s)) => s.linear_lower_to_memory(cx, ty, offset),
734            (InterfaceType::Stream(_), _) => unexpected(ty, self),
735            (InterfaceType::ErrorContext(_), Val::ErrorContext(ErrorContextAny(rep))) => {
736                concurrent::lower_error_context_to_index(*rep, cx, ty)?.linear_lower_to_memory(
737                    cx,
738                    InterfaceType::U32,
739                    offset,
740                )
741            }
742            (InterfaceType::ErrorContext(_), _) => unexpected(ty, self),
743            (InterfaceType::FixedLengthList(ty), Val::FixedLengthList(values)) => {
744                let ty = &cx.types[ty];
745                if ty.size as usize != values.len() {
746                    bail!("expected {} types, got {}", ty.size, values.len());
747                }
748                let elemsize = cx.types.canonical_abi(&ty.element).size32 as usize;
749                for (n, value) in values.iter().enumerate() {
750                    value.store(cx, ty.element, offset + elemsize * n)?;
751                }
752                Ok(())
753            }
754            (InterfaceType::FixedLengthList(_), _) => unexpected(ty, self),
755        }
756    }
757
758    pub(crate) fn desc(&self) -> &'static str {
759        match self {
760            Val::Bool(_) => "bool",
761            Val::U8(_) => "u8",
762            Val::S8(_) => "s8",
763            Val::U16(_) => "u16",
764            Val::S16(_) => "s16",
765            Val::U32(_) => "u32",
766            Val::S32(_) => "s32",
767            Val::U64(_) => "u64",
768            Val::S64(_) => "s64",
769            Val::Float32(_) => "f32",
770            Val::Float64(_) => "f64",
771            Val::Char(_) => "char",
772            Val::List(_) => "list",
773            Val::Map(_) => "map",
774            Val::String(_) => "string",
775            Val::Record(_) => "record",
776            Val::Enum(_) => "enum",
777            Val::Variant(..) => "variant",
778            Val::Tuple(_) => "tuple",
779            Val::Option(_) => "option",
780            Val::Result(_) => "result",
781            Val::Resource(_) => "resource",
782            Val::Flags(_) => "flags",
783            Val::Future(_) => "future",
784            Val::Stream(_) => "stream",
785            Val::ErrorContext(_) => "error-context",
786            Val::FixedLengthList(_) => "list<_, N>",
787        }
788    }
789
790    /// Deserialize a [`Val`] from its [`crate::component::wasm_wave`] encoding. Deserialization
791    /// requires a target [`crate::component::Type`].
792    #[cfg(feature = "wave")]
793    pub fn from_wave(ty: &crate::component::Type, s: &str) -> Result<Self> {
794        Ok(wasm_wave::from_str(ty, s)?)
795    }
796
797    /// Serialize a [`Val`] to its [`crate::component::wasm_wave`] encoding.
798    #[cfg(feature = "wave")]
799    pub fn to_wave(&self) -> Result<String> {
800        Ok(wasm_wave::to_string(self)?)
801    }
802}
803
804impl PartialEq for Val {
805    fn eq(&self, other: &Self) -> bool {
806        match (self, other) {
807            // IEEE 754 equality considers NaN inequal to NaN and negative zero
808            // equal to positive zero, however we do the opposite here, because
809            // this logic is used by testing and fuzzing, which want to know
810            // whether two values are semantically the same, rather than
811            // numerically equal.
812            (Self::Float32(l), Self::Float32(r)) => {
813                (*l != 0.0 && l == r)
814                    || (*l == 0.0 && l.to_bits() == r.to_bits())
815                    || (l.is_nan() && r.is_nan())
816            }
817            (Self::Float32(_), _) => false,
818            (Self::Float64(l), Self::Float64(r)) => {
819                (*l != 0.0 && l == r)
820                    || (*l == 0.0 && l.to_bits() == r.to_bits())
821                    || (l.is_nan() && r.is_nan())
822            }
823            (Self::Float64(_), _) => false,
824
825            (Self::Bool(l), Self::Bool(r)) => l == r,
826            (Self::Bool(_), _) => false,
827            (Self::S8(l), Self::S8(r)) => l == r,
828            (Self::S8(_), _) => false,
829            (Self::U8(l), Self::U8(r)) => l == r,
830            (Self::U8(_), _) => false,
831            (Self::S16(l), Self::S16(r)) => l == r,
832            (Self::S16(_), _) => false,
833            (Self::U16(l), Self::U16(r)) => l == r,
834            (Self::U16(_), _) => false,
835            (Self::S32(l), Self::S32(r)) => l == r,
836            (Self::S32(_), _) => false,
837            (Self::U32(l), Self::U32(r)) => l == r,
838            (Self::U32(_), _) => false,
839            (Self::S64(l), Self::S64(r)) => l == r,
840            (Self::S64(_), _) => false,
841            (Self::U64(l), Self::U64(r)) => l == r,
842            (Self::U64(_), _) => false,
843            (Self::Char(l), Self::Char(r)) => l == r,
844            (Self::Char(_), _) => false,
845            (Self::String(l), Self::String(r)) => l == r,
846            (Self::String(_), _) => false,
847            (Self::List(l), Self::List(r)) => l == r,
848            (Self::List(_), _) => false,
849            (Self::Map(l), Self::Map(r)) => l == r,
850            (Self::Map(_), _) => false,
851            (Self::Record(l), Self::Record(r)) => l == r,
852            (Self::Record(_), _) => false,
853            (Self::Tuple(l), Self::Tuple(r)) => l == r,
854            (Self::Tuple(_), _) => false,
855            (Self::Variant(ln, lv), Self::Variant(rn, rv)) => ln == rn && lv == rv,
856            (Self::Variant(..), _) => false,
857            (Self::Enum(l), Self::Enum(r)) => l == r,
858            (Self::Enum(_), _) => false,
859            (Self::Option(l), Self::Option(r)) => l == r,
860            (Self::Option(_), _) => false,
861            (Self::Result(l), Self::Result(r)) => l == r,
862            (Self::Result(_), _) => false,
863            (Self::Flags(l), Self::Flags(r)) => l == r,
864            (Self::Flags(_), _) => false,
865            (Self::Resource(l), Self::Resource(r)) => l == r,
866            (Self::Resource(_), _) => false,
867            (Self::Future(l), Self::Future(r)) => l == r,
868            (Self::Future(_), _) => false,
869            (Self::Stream(l), Self::Stream(r)) => l == r,
870            (Self::Stream(_), _) => false,
871            (Self::ErrorContext(l), Self::ErrorContext(r)) => l == r,
872            (Self::ErrorContext(_), _) => false,
873            (Self::FixedLengthList(l), Self::FixedLengthList(r)) => l == r,
874            (Self::FixedLengthList(_), _) => false,
875        }
876    }
877}
878
879impl Eq for Val {}
880
881struct GenericVariant<'a> {
882    discriminant: u32,
883    payload: Option<(&'a Val, InterfaceType)>,
884    abi: &'a CanonicalAbiInfo,
885    info: &'a VariantInfo,
886}
887
888impl GenericVariant<'_> {
889    fn result<'a>(
890        ty: &'a TypeResult,
891        r: &'a Result<Option<Box<Val>>, Option<Box<Val>>>,
892    ) -> Result<GenericVariant<'a>> {
893        let (discriminant, payload) = match r {
894            Ok(val) => {
895                let payload = match (val, ty.ok) {
896                    (Some(val), Some(ty)) => Some((&**val, ty)),
897                    (None, None) => None,
898                    (Some(_), None) => {
899                        bail!("payload provided to `ok` but not expected");
900                    }
901                    (None, Some(_)) => {
902                        bail!("payload expected to `ok` but not provided");
903                    }
904                };
905                (0, payload)
906            }
907            Err(val) => {
908                let payload = match (val, ty.err) {
909                    (Some(val), Some(ty)) => Some((&**val, ty)),
910                    (None, None) => None,
911                    (Some(_), None) => {
912                        bail!("payload provided to `err` but not expected");
913                    }
914                    (None, Some(_)) => {
915                        bail!("payload expected to `err` but not provided");
916                    }
917                };
918                (1, payload)
919            }
920        };
921        Ok(GenericVariant {
922            discriminant,
923            payload,
924            abi: &ty.abi,
925            info: &ty.info,
926        })
927    }
928
929    fn option<'a>(ty: &'a TypeOption, r: &'a Option<Box<Val>>) -> GenericVariant<'a> {
930        let (discriminant, payload) = match r {
931            None => (0, None),
932            Some(val) => (1, Some((&**val, ty.ty))),
933        };
934        GenericVariant {
935            discriminant,
936            payload,
937            abi: &ty.abi,
938            info: &ty.info,
939        }
940    }
941
942    fn enum_<'a>(ty: &'a TypeEnum, discriminant: &str) -> Result<GenericVariant<'a>> {
943        let discriminant = get_enum_discriminant(ty, discriminant)?;
944
945        Ok(GenericVariant {
946            discriminant,
947            payload: None,
948            abi: &ty.abi,
949            info: &ty.info,
950        })
951    }
952
953    fn variant<'a>(
954        ty: &'a TypeVariant,
955        discriminant_name: &str,
956        payload: &'a Option<Box<Val>>,
957    ) -> Result<GenericVariant<'a>> {
958        let (discriminant, payload_ty) = get_variant_discriminant(ty, discriminant_name)?;
959
960        let payload = match (payload, payload_ty) {
961            (Some(val), Some(ty)) => Some((&**val, *ty)),
962            (None, None) => None,
963            (Some(_), None) => bail!("did not expect a payload for case `{discriminant_name}`"),
964            (None, Some(_)) => bail!("expected a payload for case `{discriminant_name}`"),
965        };
966
967        Ok(GenericVariant {
968            discriminant,
969            payload,
970            abi: &ty.abi,
971            info: &ty.info,
972        })
973    }
974
975    fn lower<T>(
976        &self,
977        cx: &mut LowerContext<'_, T>,
978        dst: &mut IterMut<'_, MaybeUninit<ValRaw>>,
979    ) -> Result<()> {
980        next_mut(dst).write(ValRaw::u32(self.discriminant));
981
982        // For the remaining lowered representation of this variant that
983        // the payload didn't write we write out zeros here to ensure
984        // the entire variant is written.
985        let value_flat = match self.payload {
986            Some((value, ty)) => {
987                value.lower(cx, ty, dst)?;
988                cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap()
989            }
990            None => 0,
991        };
992        let variant_flat = self.abi.flat_count(usize::MAX).unwrap();
993        for _ in (1 + value_flat)..variant_flat {
994            next_mut(dst).write(ValRaw::u64(0));
995        }
996        Ok(())
997    }
998
999    fn store<T>(&self, cx: &mut LowerContext<'_, T>, offset: usize) -> Result<()> {
1000        match self.info.size {
1001            DiscriminantSize::Size1 => u8::try_from(self.discriminant)
1002                .unwrap()
1003                .linear_lower_to_memory(cx, InterfaceType::U8, offset)?,
1004            DiscriminantSize::Size2 => u16::try_from(self.discriminant)
1005                .unwrap()
1006                .linear_lower_to_memory(cx, InterfaceType::U16, offset)?,
1007            DiscriminantSize::Size4 => {
1008                self.discriminant
1009                    .linear_lower_to_memory(cx, InterfaceType::U32, offset)?
1010            }
1011        }
1012
1013        if let Some((value, ty)) = self.payload {
1014            let offset = offset + usize::try_from(self.info.payload_offset32).unwrap();
1015            value.store(cx, ty, offset)?;
1016        }
1017
1018        Ok(())
1019    }
1020}
1021
1022fn lift_flat_pointer_pair(
1023    cx: &mut LiftContext<'_>,
1024    src: &mut Iter<'_, ValRaw>,
1025) -> Result<(usize, usize)> {
1026    // FIXME(#4311): needs memory64 treatment
1027    let ptr = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize;
1028    let len = u32::linear_lift_from_flat(cx, InterfaceType::U32, next(src))? as usize;
1029    Ok((ptr, len))
1030}
1031
1032fn load_flat_pointer_pair(bytes: &[u8]) -> (usize, usize) {
1033    let ptr = u32::from_le_bytes(*bytes[..4].as_array().unwrap()) as usize;
1034    let len = u32::from_le_bytes(*bytes[4..].as_array().unwrap()) as usize;
1035    (ptr, len)
1036}
1037
1038fn load_list(cx: &mut LiftContext<'_>, ty: TypeListIndex, ptr: usize, len: usize) -> Result<Val> {
1039    let elem = cx.types[ty].element;
1040    let abi = cx.types.canonical_abi(&elem);
1041    let element_size = usize::try_from(abi.size32).unwrap();
1042    let element_alignment = abi.align32;
1043
1044    match len
1045        .checked_mul(element_size)
1046        .and_then(|len| ptr.checked_add(len))
1047    {
1048        Some(n) if n <= cx.memory().len() => cx.consume_fuel_array(len, size_of::<Val>())?,
1049        _ => bail!("list pointer/length out of bounds of memory"),
1050    }
1051    if ptr % usize::try_from(element_alignment)? != 0 {
1052        bail!("list pointer is not aligned")
1053    }
1054
1055    Ok(Val::List(
1056        (0..len)
1057            .map(|index| {
1058                Val::load(
1059                    cx,
1060                    elem,
1061                    &cx.memory()[ptr + (index * element_size)..][..element_size],
1062                )
1063            })
1064            .collect::<Result<_>>()?,
1065    ))
1066}
1067
1068fn load_map(cx: &mut LiftContext<'_>, ty: TypeMapIndex, ptr: usize, len: usize) -> Result<Val> {
1069    // Maps are stored as list<tuple<k, v>> in canonical ABI
1070    let map_ty = &cx.types[ty];
1071    let key_ty = map_ty.key;
1072    let value_ty = map_ty.value;
1073
1074    let key_abi = cx.types.canonical_abi(&key_ty);
1075    let value_abi = cx.types.canonical_abi(&value_ty);
1076    let key_size = usize::try_from(key_abi.size32).unwrap();
1077    let value_size = usize::try_from(value_abi.size32).unwrap();
1078    let value_offset = usize::try_from(map_ty.value_offset32).unwrap();
1079    let tuple_alignment = map_ty.entry_abi.align32;
1080    let tuple_size = usize::try_from(map_ty.entry_abi.size32).unwrap();
1081
1082    // Bounds check
1083    match len
1084        .checked_mul(tuple_size)
1085        .and_then(|len| ptr.checked_add(len))
1086    {
1087        Some(n) if n <= cx.memory().len() => cx.consume_fuel_array(len, size_of::<(Val, Val)>())?,
1088        _ => bail!("map pointer/length out of bounds of memory"),
1089    }
1090    if ptr % usize::try_from(tuple_alignment)? != 0 {
1091        bail!("map pointer is not aligned")
1092    }
1093
1094    // Load each tuple (key, value) into a Vec
1095    let mut map = Vec::with_capacity(len);
1096    for index in 0..len {
1097        let tuple_ptr = ptr + (index * tuple_size);
1098        let key = Val::load(cx, key_ty, &cx.memory()[tuple_ptr..][..key_size])?;
1099        let value = Val::load(
1100            cx,
1101            value_ty,
1102            &cx.memory()[tuple_ptr + value_offset..][..value_size],
1103        )?;
1104        map.push((key, value));
1105    }
1106
1107    Ok(Val::Map(map))
1108}
1109
1110fn load_variant(
1111    cx: &mut LiftContext<'_>,
1112    info: &VariantInfo,
1113    mut types: impl ExactSizeIterator<Item = Option<InterfaceType>>,
1114    bytes: &[u8],
1115) -> Result<(u32, Option<Box<Val>>)> {
1116    let discriminant = match info.size {
1117        DiscriminantSize::Size1 => u32::from(u8::linear_lift_from_memory(
1118            cx,
1119            InterfaceType::U8,
1120            &bytes[..1],
1121        )?),
1122        DiscriminantSize::Size2 => u32::from(u16::linear_lift_from_memory(
1123            cx,
1124            InterfaceType::U16,
1125            &bytes[..2],
1126        )?),
1127        DiscriminantSize::Size4 => {
1128            u32::linear_lift_from_memory(cx, InterfaceType::U32, &bytes[..4])?
1129        }
1130    };
1131    let len = types.len();
1132    let case_ty = types
1133        .nth(discriminant as usize)
1134        .ok_or_else(|| format_err!("discriminant {discriminant} out of range [0..{len})"))?;
1135    let value = match case_ty {
1136        Some(case_ty) => {
1137            cx.consume_fuel(size_of::<Val>())?;
1138            let payload_offset = usize::try_from(info.payload_offset32).unwrap();
1139            let case_abi = cx.types.canonical_abi(&case_ty);
1140            let case_size = usize::try_from(case_abi.size32).unwrap();
1141            Some(Box::new(Val::load(
1142                cx,
1143                case_ty,
1144                &bytes[payload_offset..][..case_size],
1145            )?))
1146        }
1147        None => None,
1148    };
1149    Ok((discriminant, value))
1150}
1151
1152fn lift_variant(
1153    cx: &mut LiftContext<'_>,
1154    flatten_count: usize,
1155    mut types: impl ExactSizeIterator<Item = Option<InterfaceType>>,
1156    src: &mut Iter<'_, ValRaw>,
1157) -> Result<(u32, Option<Box<Val>>)> {
1158    let len = types.len();
1159    let discriminant = next(src).get_u32();
1160    let ty = types
1161        .nth(discriminant as usize)
1162        .ok_or_else(|| format_err!("discriminant {discriminant} out of range [0..{len})"))?;
1163    let (value, value_flat) = match ty {
1164        Some(ty) => {
1165            cx.consume_fuel(size_of::<Val>())?;
1166            (
1167                Some(Box::new(Val::lift(cx, ty, src)?)),
1168                cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
1169            )
1170        }
1171        None => (None, 0),
1172    };
1173    for _ in (1 + value_flat)..flatten_count {
1174        next(src);
1175    }
1176    Ok((discriminant, value))
1177}
1178
1179/// Lower a list with the specified element type and values.
1180fn lower_list<T>(
1181    cx: &mut LowerContext<'_, T>,
1182    element_type: InterfaceType,
1183    items: &[Val],
1184) -> Result<(usize, usize)> {
1185    let abi = cx.types.canonical_abi(&element_type);
1186    let elt_size = usize::try_from(abi.size32)?;
1187    let elt_align = abi.align32;
1188    let size = items
1189        .len()
1190        .checked_mul(elt_size)
1191        .ok_or_else(|| crate::format_err!("size overflow copying a list"))?;
1192    let ptr = cx.realloc(0, 0, elt_align, size)?;
1193    let mut element_ptr = ptr;
1194    for item in items {
1195        item.store(cx, element_type, element_ptr)?;
1196        element_ptr += elt_size;
1197    }
1198    Ok((ptr, items.len()))
1199}
1200
1201/// Lower a map as list<tuple<k, v>> with the specified key and value types.
1202fn lower_map<T>(
1203    cx: &mut LowerContext<'_, T>,
1204    map_ty: &TypeMap,
1205    pairs: &[(Val, Val)],
1206) -> Result<(usize, usize)> {
1207    let key_type = map_ty.key;
1208    let value_type = map_ty.value;
1209    let value_offset = usize::try_from(map_ty.value_offset32).unwrap();
1210    let tuple_align = map_ty.entry_abi.align32;
1211    let tuple_size = usize::try_from(map_ty.entry_abi.size32).unwrap();
1212
1213    let size = pairs
1214        .len()
1215        .checked_mul(tuple_size)
1216        .ok_or_else(|| crate::format_err!("size overflow copying a map"))?;
1217    let ptr = cx.realloc(0, 0, tuple_align, size)?;
1218
1219    let mut tuple_ptr = ptr;
1220    for (key, value) in pairs {
1221        // Store key at tuple_ptr
1222        key.store(cx, key_type, tuple_ptr)?;
1223        // Store value at tuple_ptr + value_offset (properly aligned)
1224        value.store(cx, value_type, tuple_ptr + value_offset)?;
1225        tuple_ptr += tuple_size;
1226    }
1227
1228    Ok((ptr, pairs.len()))
1229}
1230
1231fn push_flags(
1232    cx: &mut LiftContext<'_>,
1233    ty: &TypeFlags,
1234    flags: &mut Vec<String>,
1235    mut offset: u32,
1236    mut bits: u32,
1237) -> Result<()> {
1238    while bits > 0 && usize::try_from(offset).unwrap() < ty.names.len() {
1239        if bits & 1 != 0 {
1240            let name = &ty.names[offset as usize];
1241            cx.consume_fuel(name.len())?;
1242            flags.push(name.to_string());
1243        }
1244        bits >>= 1;
1245        offset += 1;
1246    }
1247    Ok(())
1248}
1249
1250fn flags_to_storage(ty: &TypeFlags, flags: &[String]) -> Result<Vec<u32>> {
1251    let mut storage = match FlagsSize::from_count(ty.names.len()) {
1252        FlagsSize::Size0 => Vec::new(),
1253        FlagsSize::Size1 | FlagsSize::Size2 => vec![0],
1254        FlagsSize::Size4Plus(n) => vec![0; n.into()],
1255    };
1256
1257    for flag in flags {
1258        let bit = ty
1259            .names
1260            .get_index_of(flag.as_str())
1261            .ok_or_else(|| crate::format_err!("unknown flag: `{flag}`"))?;
1262        storage[bit / 32] |= 1 << (bit % 32);
1263    }
1264    Ok(storage)
1265}
1266
1267fn get_enum_discriminant(ty: &TypeEnum, n: &str) -> Result<u32> {
1268    ty.names
1269        .get_index_of(n)
1270        .ok_or_else(|| crate::format_err!("enum variant name `{n}` is not valid"))
1271        .map(|i| i.try_into().unwrap())
1272}
1273
1274fn get_variant_discriminant<'a>(
1275    ty: &'a TypeVariant,
1276    name: &str,
1277) -> Result<(u32, &'a Option<InterfaceType>)> {
1278    let (i, _, ty) = ty
1279        .cases
1280        .get_full(name)
1281        .ok_or_else(|| crate::format_err!("unknown variant case: `{name}`"))?;
1282    Ok((i.try_into().unwrap(), ty))
1283}
1284
1285fn next<'a>(src: &mut Iter<'a, ValRaw>) -> &'a ValRaw {
1286    src.next().unwrap()
1287}
1288
1289fn next_mut<'a>(dst: &mut IterMut<'a, MaybeUninit<ValRaw>>) -> &'a mut MaybeUninit<ValRaw> {
1290    dst.next().unwrap()
1291}
1292
1293#[cold]
1294fn unexpected<T>(ty: InterfaceType, val: &Val) -> Result<T> {
1295    bail!(
1296        "type mismatch: expected {}, found {}",
1297        desc(&ty),
1298        val.desc()
1299    )
1300}
1301
1302/// Represents a component model `error-context`.
1303///
1304/// Note that this type is not usable at this time as its implementation has not
1305/// been filled out. There are no operations on this and there's additionally no
1306/// ability to "drop" or deallocate this index.
1307//
1308// FIXME(#11161) this needs to be filled out implementation-wise
1309#[derive(Debug, Clone, PartialEq, Eq)]
1310pub struct ErrorContextAny(pub(crate) u32);
1311
1312impl From<bool> for Val {
1313    fn from(b: bool) -> Self {
1314        Val::Bool(b)
1315    }
1316}
1317
1318impl From<u8> for Val {
1319    fn from(u: u8) -> Self {
1320        Val::U8(u)
1321    }
1322}
1323
1324impl From<i8> for Val {
1325    fn from(i: i8) -> Self {
1326        Val::S8(i)
1327    }
1328}
1329
1330impl From<u16> for Val {
1331    fn from(u: u16) -> Self {
1332        Val::U16(u)
1333    }
1334}
1335
1336impl From<i16> for Val {
1337    fn from(i: i16) -> Self {
1338        Val::S16(i)
1339    }
1340}
1341
1342impl From<u32> for Val {
1343    fn from(u: u32) -> Self {
1344        Val::U32(u)
1345    }
1346}
1347
1348impl From<i32> for Val {
1349    fn from(i: i32) -> Self {
1350        Val::S32(i)
1351    }
1352}
1353
1354impl From<u64> for Val {
1355    fn from(u: u64) -> Self {
1356        Val::U64(u)
1357    }
1358}
1359
1360impl From<i64> for Val {
1361    fn from(i: i64) -> Self {
1362        Val::S64(i)
1363    }
1364}
1365
1366impl From<char> for Val {
1367    fn from(i: char) -> Self {
1368        Val::Char(i)
1369    }
1370}
1371
1372impl From<String> for Val {
1373    fn from(i: String) -> Self {
1374        Val::String(i)
1375    }
1376}
1377
1378impl From<ResourceAny> for Val {
1379    fn from(i: ResourceAny) -> Self {
1380        Val::Resource(i)
1381    }
1382}
1383
1384impl From<FutureAny> for Val {
1385    fn from(i: FutureAny) -> Self {
1386        Val::Future(i)
1387    }
1388}
1389
1390impl From<StreamAny> for Val {
1391    fn from(i: StreamAny) -> Self {
1392        Val::Stream(i)
1393    }
1394}