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