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