wasmtime/runtime/component/
values.rs

1use crate::ValRaw;
2use crate::component::ResourceAny;
3use crate::component::concurrent::{self, ErrorContext, FutureReader, StreamReader};
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                FutureReader::<()>::linear_lift_from_flat(cx, ty, next(src))?.into_val()
211            }
212            InterfaceType::Stream(_) => {
213                StreamReader::<()>::linear_lift_from_flat(cx, ty, next(src))?.into_val()
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(_) => {
340                FutureReader::<()>::linear_lift_from_memory(cx, ty, bytes)?.into_val()
341            }
342            InterfaceType::Stream(_) => {
343                StreamReader::<()>::linear_lift_from_memory(cx, ty, bytes)?.into_val()
344            }
345            InterfaceType::ErrorContext(_) => {
346                ErrorContext::linear_lift_from_memory(cx, ty, bytes)?.into_val()
347            }
348        })
349    }
350
351    /// Serialize this value as core Wasm stack values.
352    pub(crate) fn lower<T>(
353        &self,
354        cx: &mut LowerContext<'_, T>,
355        ty: InterfaceType,
356        dst: &mut IterMut<'_, MaybeUninit<ValRaw>>,
357    ) -> Result<()> {
358        match (ty, self) {
359            (InterfaceType::Bool, Val::Bool(value)) => {
360                value.linear_lower_to_flat(cx, ty, next_mut(dst))
361            }
362            (InterfaceType::Bool, _) => unexpected(ty, self),
363            (InterfaceType::S8, Val::S8(value)) => {
364                value.linear_lower_to_flat(cx, ty, next_mut(dst))
365            }
366            (InterfaceType::S8, _) => unexpected(ty, self),
367            (InterfaceType::U8, Val::U8(value)) => {
368                value.linear_lower_to_flat(cx, ty, next_mut(dst))
369            }
370            (InterfaceType::U8, _) => unexpected(ty, self),
371            (InterfaceType::S16, Val::S16(value)) => {
372                value.linear_lower_to_flat(cx, ty, next_mut(dst))
373            }
374            (InterfaceType::S16, _) => unexpected(ty, self),
375            (InterfaceType::U16, Val::U16(value)) => {
376                value.linear_lower_to_flat(cx, ty, next_mut(dst))
377            }
378            (InterfaceType::U16, _) => unexpected(ty, self),
379            (InterfaceType::S32, Val::S32(value)) => {
380                value.linear_lower_to_flat(cx, ty, next_mut(dst))
381            }
382            (InterfaceType::S32, _) => unexpected(ty, self),
383            (InterfaceType::U32, Val::U32(value)) => {
384                value.linear_lower_to_flat(cx, ty, next_mut(dst))
385            }
386            (InterfaceType::U32, _) => unexpected(ty, self),
387            (InterfaceType::S64, Val::S64(value)) => {
388                value.linear_lower_to_flat(cx, ty, next_mut(dst))
389            }
390            (InterfaceType::S64, _) => unexpected(ty, self),
391            (InterfaceType::U64, Val::U64(value)) => {
392                value.linear_lower_to_flat(cx, ty, next_mut(dst))
393            }
394            (InterfaceType::U64, _) => unexpected(ty, self),
395            (InterfaceType::Float32, Val::Float32(value)) => {
396                value.linear_lower_to_flat(cx, ty, next_mut(dst))
397            }
398            (InterfaceType::Float32, _) => unexpected(ty, self),
399            (InterfaceType::Float64, Val::Float64(value)) => {
400                value.linear_lower_to_flat(cx, ty, next_mut(dst))
401            }
402            (InterfaceType::Float64, _) => unexpected(ty, self),
403            (InterfaceType::Char, Val::Char(value)) => {
404                value.linear_lower_to_flat(cx, ty, next_mut(dst))
405            }
406            (InterfaceType::Char, _) => unexpected(ty, self),
407            // NB: `lower` on `ResourceAny` does its own type-checking, so skip
408            // looking at it here.
409            (InterfaceType::Borrow(_) | InterfaceType::Own(_), Val::Resource(value)) => {
410                value.linear_lower_to_flat(cx, ty, next_mut(dst))
411            }
412            (InterfaceType::Borrow(_) | InterfaceType::Own(_), _) => unexpected(ty, self),
413            (InterfaceType::String, Val::String(value)) => {
414                let my_dst = &mut MaybeUninit::<[ValRaw; 2]>::uninit();
415                value.linear_lower_to_flat(cx, ty, my_dst)?;
416                let my_dst = unsafe { my_dst.assume_init() };
417                next_mut(dst).write(my_dst[0]);
418                next_mut(dst).write(my_dst[1]);
419                Ok(())
420            }
421            (InterfaceType::String, _) => unexpected(ty, self),
422            (InterfaceType::List(ty), Val::List(values)) => {
423                let ty = &cx.types[ty];
424                let (ptr, len) = lower_list(cx, ty.element, values)?;
425                next_mut(dst).write(ValRaw::i64(ptr as i64));
426                next_mut(dst).write(ValRaw::i64(len as i64));
427                Ok(())
428            }
429            (InterfaceType::List(_), _) => unexpected(ty, self),
430            (InterfaceType::Record(ty), Val::Record(values)) => {
431                let ty = &cx.types[ty];
432                if ty.fields.len() != values.len() {
433                    bail!("expected {} fields, got {}", ty.fields.len(), values.len());
434                }
435                for ((name, value), field) in values.iter().zip(ty.fields.iter()) {
436                    if *name != field.name {
437                        bail!("expected field `{}`, got `{name}`", field.name);
438                    }
439                    value.lower(cx, field.ty, dst)?;
440                }
441                Ok(())
442            }
443            (InterfaceType::Record(_), _) => unexpected(ty, self),
444            (InterfaceType::Tuple(ty), Val::Tuple(values)) => {
445                let ty = &cx.types[ty];
446                if ty.types.len() != values.len() {
447                    bail!("expected {} types, got {}", ty.types.len(), values.len());
448                }
449                for (value, ty) in values.iter().zip(ty.types.iter()) {
450                    value.lower(cx, *ty, dst)?;
451                }
452                Ok(())
453            }
454            (InterfaceType::Tuple(_), _) => unexpected(ty, self),
455            (InterfaceType::Variant(ty), Val::Variant(n, v)) => {
456                GenericVariant::variant(&cx.types[ty], n, v)?.lower(cx, dst)
457            }
458            (InterfaceType::Variant(_), _) => unexpected(ty, self),
459            (InterfaceType::Option(ty), Val::Option(v)) => {
460                GenericVariant::option(&cx.types[ty], v).lower(cx, dst)
461            }
462            (InterfaceType::Option(_), _) => unexpected(ty, self),
463            (InterfaceType::Result(ty), Val::Result(v)) => {
464                GenericVariant::result(&cx.types[ty], v)?.lower(cx, dst)
465            }
466            (InterfaceType::Result(_), _) => unexpected(ty, self),
467            (InterfaceType::Enum(ty), Val::Enum(discriminant)) => {
468                let discriminant = get_enum_discriminant(&cx.types[ty], discriminant)?;
469                next_mut(dst).write(ValRaw::u32(discriminant));
470                Ok(())
471            }
472            (InterfaceType::Enum(_), _) => unexpected(ty, self),
473            (InterfaceType::Flags(ty), Val::Flags(value)) => {
474                let ty = &cx.types[ty];
475                let storage = flags_to_storage(ty, value)?;
476                for value in storage {
477                    next_mut(dst).write(ValRaw::u32(value));
478                }
479                Ok(())
480            }
481            (InterfaceType::Flags(_), _) => unexpected(ty, self),
482            (InterfaceType::Future(_), Val::Future(FutureAny(rep))) => {
483                concurrent::lower_future_to_index(*rep, cx, ty)?.linear_lower_to_flat(
484                    cx,
485                    InterfaceType::U32,
486                    next_mut(dst),
487                )
488            }
489            (InterfaceType::Future(_), _) => unexpected(ty, self),
490            (InterfaceType::Stream(_), Val::Stream(StreamAny(rep))) => {
491                concurrent::lower_stream_to_index(*rep, cx, ty)?.linear_lower_to_flat(
492                    cx,
493                    InterfaceType::U32,
494                    next_mut(dst),
495                )
496            }
497            (InterfaceType::Stream(_), _) => unexpected(ty, self),
498            (InterfaceType::ErrorContext(_), Val::ErrorContext(ErrorContextAny(rep))) => {
499                concurrent::lower_error_context_to_index(*rep, cx, ty)?.linear_lower_to_flat(
500                    cx,
501                    InterfaceType::U32,
502                    next_mut(dst),
503                )
504            }
505            (InterfaceType::ErrorContext(_), _) => unexpected(ty, self),
506        }
507    }
508
509    /// Serialize this value to the heap at the specified memory location.
510    pub(crate) fn store<T>(
511        &self,
512        cx: &mut LowerContext<'_, T>,
513        ty: InterfaceType,
514        offset: usize,
515    ) -> Result<()> {
516        debug_assert!(offset % usize::try_from(cx.types.canonical_abi(&ty).align32)? == 0);
517
518        match (ty, self) {
519            (InterfaceType::Bool, Val::Bool(value)) => value.linear_lower_to_memory(cx, ty, offset),
520            (InterfaceType::Bool, _) => unexpected(ty, self),
521            (InterfaceType::U8, Val::U8(value)) => value.linear_lower_to_memory(cx, ty, offset),
522            (InterfaceType::U8, _) => unexpected(ty, self),
523            (InterfaceType::S8, Val::S8(value)) => value.linear_lower_to_memory(cx, ty, offset),
524            (InterfaceType::S8, _) => unexpected(ty, self),
525            (InterfaceType::U16, Val::U16(value)) => value.linear_lower_to_memory(cx, ty, offset),
526            (InterfaceType::U16, _) => unexpected(ty, self),
527            (InterfaceType::S16, Val::S16(value)) => value.linear_lower_to_memory(cx, ty, offset),
528            (InterfaceType::S16, _) => unexpected(ty, self),
529            (InterfaceType::U32, Val::U32(value)) => value.linear_lower_to_memory(cx, ty, offset),
530            (InterfaceType::U32, _) => unexpected(ty, self),
531            (InterfaceType::S32, Val::S32(value)) => value.linear_lower_to_memory(cx, ty, offset),
532            (InterfaceType::S32, _) => unexpected(ty, self),
533            (InterfaceType::U64, Val::U64(value)) => value.linear_lower_to_memory(cx, ty, offset),
534            (InterfaceType::U64, _) => unexpected(ty, self),
535            (InterfaceType::S64, Val::S64(value)) => value.linear_lower_to_memory(cx, ty, offset),
536            (InterfaceType::S64, _) => unexpected(ty, self),
537            (InterfaceType::Float32, Val::Float32(value)) => {
538                value.linear_lower_to_memory(cx, ty, offset)
539            }
540            (InterfaceType::Float32, _) => unexpected(ty, self),
541            (InterfaceType::Float64, Val::Float64(value)) => {
542                value.linear_lower_to_memory(cx, ty, offset)
543            }
544            (InterfaceType::Float64, _) => unexpected(ty, self),
545            (InterfaceType::Char, Val::Char(value)) => value.linear_lower_to_memory(cx, ty, offset),
546            (InterfaceType::Char, _) => unexpected(ty, self),
547            (InterfaceType::String, Val::String(value)) => {
548                value.linear_lower_to_memory(cx, ty, offset)
549            }
550            (InterfaceType::String, _) => unexpected(ty, self),
551
552            // NB: resources do type-checking when they lower.
553            (InterfaceType::Borrow(_) | InterfaceType::Own(_), Val::Resource(value)) => {
554                value.linear_lower_to_memory(cx, ty, offset)
555            }
556            (InterfaceType::Borrow(_) | InterfaceType::Own(_), _) => unexpected(ty, self),
557            (InterfaceType::List(ty), Val::List(values)) => {
558                let ty = &cx.types[ty];
559                let (ptr, len) = lower_list(cx, ty.element, values)?;
560                // FIXME(#4311): needs memory64 handling
561                *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes();
562                *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes();
563                Ok(())
564            }
565            (InterfaceType::List(_), _) => unexpected(ty, self),
566            (InterfaceType::Record(ty), Val::Record(values)) => {
567                let ty = &cx.types[ty];
568                if ty.fields.len() != values.len() {
569                    bail!("expected {} fields, got {}", ty.fields.len(), values.len());
570                }
571                let mut offset = offset;
572                for ((name, value), field) in values.iter().zip(ty.fields.iter()) {
573                    if *name != field.name {
574                        bail!("expected field `{}`, got `{name}`", field.name);
575                    }
576                    value.store(
577                        cx,
578                        field.ty,
579                        cx.types
580                            .canonical_abi(&field.ty)
581                            .next_field32_size(&mut offset),
582                    )?;
583                }
584                Ok(())
585            }
586            (InterfaceType::Record(_), _) => unexpected(ty, self),
587            (InterfaceType::Tuple(ty), Val::Tuple(values)) => {
588                let ty = &cx.types[ty];
589                if ty.types.len() != values.len() {
590                    bail!("expected {} types, got {}", ty.types.len(), values.len());
591                }
592                let mut offset = offset;
593                for (value, ty) in values.iter().zip(ty.types.iter()) {
594                    value.store(
595                        cx,
596                        *ty,
597                        cx.types.canonical_abi(ty).next_field32_size(&mut offset),
598                    )?;
599                }
600                Ok(())
601            }
602            (InterfaceType::Tuple(_), _) => unexpected(ty, self),
603
604            (InterfaceType::Variant(ty), Val::Variant(n, v)) => {
605                GenericVariant::variant(&cx.types[ty], n, v)?.store(cx, offset)
606            }
607            (InterfaceType::Variant(_), _) => unexpected(ty, self),
608            (InterfaceType::Enum(ty), Val::Enum(v)) => {
609                GenericVariant::enum_(&cx.types[ty], v)?.store(cx, offset)
610            }
611            (InterfaceType::Enum(_), _) => unexpected(ty, self),
612            (InterfaceType::Option(ty), Val::Option(v)) => {
613                GenericVariant::option(&cx.types[ty], v).store(cx, offset)
614            }
615            (InterfaceType::Option(_), _) => unexpected(ty, self),
616            (InterfaceType::Result(ty), Val::Result(v)) => {
617                GenericVariant::result(&cx.types[ty], v)?.store(cx, offset)
618            }
619            (InterfaceType::Result(_), _) => unexpected(ty, self),
620
621            (InterfaceType::Flags(ty), Val::Flags(flags)) => {
622                let ty = &cx.types[ty];
623                let storage = flags_to_storage(ty, flags)?;
624                match FlagsSize::from_count(ty.names.len()) {
625                    FlagsSize::Size0 => {}
626                    FlagsSize::Size1 => u8::try_from(storage[0]).unwrap().linear_lower_to_memory(
627                        cx,
628                        InterfaceType::U8,
629                        offset,
630                    )?,
631                    FlagsSize::Size2 => u16::try_from(storage[0]).unwrap().linear_lower_to_memory(
632                        cx,
633                        InterfaceType::U16,
634                        offset,
635                    )?,
636                    FlagsSize::Size4Plus(_) => {
637                        let mut offset = offset;
638                        for value in storage {
639                            value.linear_lower_to_memory(cx, InterfaceType::U32, offset)?;
640                            offset += 4;
641                        }
642                    }
643                }
644                Ok(())
645            }
646            (InterfaceType::Flags(_), _) => unexpected(ty, self),
647            (InterfaceType::Future(_), Val::Future(FutureAny(rep))) => {
648                concurrent::lower_future_to_index::<T>(*rep, cx, ty)?.linear_lower_to_memory(
649                    cx,
650                    InterfaceType::U32,
651                    offset,
652                )
653            }
654            (InterfaceType::Future(_), _) => unexpected(ty, self),
655            (InterfaceType::Stream(_), Val::Stream(StreamAny(rep))) => {
656                concurrent::lower_stream_to_index::<T>(*rep, cx, ty)?.linear_lower_to_memory(
657                    cx,
658                    InterfaceType::U32,
659                    offset,
660                )
661            }
662            (InterfaceType::Stream(_), _) => unexpected(ty, self),
663            (InterfaceType::ErrorContext(_), Val::ErrorContext(ErrorContextAny(rep))) => {
664                concurrent::lower_error_context_to_index(*rep, cx, ty)?.linear_lower_to_memory(
665                    cx,
666                    InterfaceType::U32,
667                    offset,
668                )
669            }
670            (InterfaceType::ErrorContext(_), _) => unexpected(ty, self),
671        }
672    }
673
674    pub(crate) fn desc(&self) -> &'static str {
675        match self {
676            Val::Bool(_) => "bool",
677            Val::U8(_) => "u8",
678            Val::S8(_) => "s8",
679            Val::U16(_) => "u16",
680            Val::S16(_) => "s16",
681            Val::U32(_) => "u32",
682            Val::S32(_) => "s32",
683            Val::U64(_) => "u64",
684            Val::S64(_) => "s64",
685            Val::Float32(_) => "f32",
686            Val::Float64(_) => "f64",
687            Val::Char(_) => "char",
688            Val::List(_) => "list",
689            Val::String(_) => "string",
690            Val::Record(_) => "record",
691            Val::Enum(_) => "enum",
692            Val::Variant(..) => "variant",
693            Val::Tuple(_) => "tuple",
694            Val::Option(_) => "option",
695            Val::Result(_) => "result",
696            Val::Resource(_) => "resource",
697            Val::Flags(_) => "flags",
698            Val::Future(_) => "future",
699            Val::Stream(_) => "stream",
700            Val::ErrorContext(_) => "error-context",
701        }
702    }
703
704    /// Deserialize a [`Val`] from its [`crate::component::wasm_wave`] encoding. Deserialization
705    /// requires a target [`crate::component::Type`].
706    #[cfg(feature = "wave")]
707    pub fn from_wave(ty: &crate::component::Type, s: &str) -> Result<Self> {
708        Ok(wasm_wave::from_str(ty, s)?)
709    }
710
711    /// Serialize a [`Val`] to its [`crate::component::wasm_wave`] encoding.
712    #[cfg(feature = "wave")]
713    pub fn to_wave(&self) -> Result<String> {
714        Ok(wasm_wave::to_string(self)?)
715    }
716}
717
718impl PartialEq for Val {
719    fn eq(&self, other: &Self) -> bool {
720        match (self, other) {
721            // IEEE 754 equality considers NaN inequal to NaN and negative zero
722            // equal to positive zero, however we do the opposite here, because
723            // this logic is used by testing and fuzzing, which want to know
724            // whether two values are semantically the same, rather than
725            // numerically equal.
726            (Self::Float32(l), Self::Float32(r)) => {
727                (*l != 0.0 && l == r)
728                    || (*l == 0.0 && l.to_bits() == r.to_bits())
729                    || (l.is_nan() && r.is_nan())
730            }
731            (Self::Float32(_), _) => false,
732            (Self::Float64(l), Self::Float64(r)) => {
733                (*l != 0.0 && l == r)
734                    || (*l == 0.0 && l.to_bits() == r.to_bits())
735                    || (l.is_nan() && r.is_nan())
736            }
737            (Self::Float64(_), _) => false,
738
739            (Self::Bool(l), Self::Bool(r)) => l == r,
740            (Self::Bool(_), _) => false,
741            (Self::S8(l), Self::S8(r)) => l == r,
742            (Self::S8(_), _) => false,
743            (Self::U8(l), Self::U8(r)) => l == r,
744            (Self::U8(_), _) => false,
745            (Self::S16(l), Self::S16(r)) => l == r,
746            (Self::S16(_), _) => false,
747            (Self::U16(l), Self::U16(r)) => l == r,
748            (Self::U16(_), _) => false,
749            (Self::S32(l), Self::S32(r)) => l == r,
750            (Self::S32(_), _) => false,
751            (Self::U32(l), Self::U32(r)) => l == r,
752            (Self::U32(_), _) => false,
753            (Self::S64(l), Self::S64(r)) => l == r,
754            (Self::S64(_), _) => false,
755            (Self::U64(l), Self::U64(r)) => l == r,
756            (Self::U64(_), _) => false,
757            (Self::Char(l), Self::Char(r)) => l == r,
758            (Self::Char(_), _) => false,
759            (Self::String(l), Self::String(r)) => l == r,
760            (Self::String(_), _) => false,
761            (Self::List(l), Self::List(r)) => l == r,
762            (Self::List(_), _) => false,
763            (Self::Record(l), Self::Record(r)) => l == r,
764            (Self::Record(_), _) => false,
765            (Self::Tuple(l), Self::Tuple(r)) => l == r,
766            (Self::Tuple(_), _) => false,
767            (Self::Variant(ln, lv), Self::Variant(rn, rv)) => ln == rn && lv == rv,
768            (Self::Variant(..), _) => false,
769            (Self::Enum(l), Self::Enum(r)) => l == r,
770            (Self::Enum(_), _) => false,
771            (Self::Option(l), Self::Option(r)) => l == r,
772            (Self::Option(_), _) => false,
773            (Self::Result(l), Self::Result(r)) => l == r,
774            (Self::Result(_), _) => false,
775            (Self::Flags(l), Self::Flags(r)) => l == r,
776            (Self::Flags(_), _) => false,
777            (Self::Resource(l), Self::Resource(r)) => l == r,
778            (Self::Resource(_), _) => false,
779            (Self::Future(l), Self::Future(r)) => l == r,
780            (Self::Future(_), _) => false,
781            (Self::Stream(l), Self::Stream(r)) => l == r,
782            (Self::Stream(_), _) => false,
783            (Self::ErrorContext(l), Self::ErrorContext(r)) => l == r,
784            (Self::ErrorContext(_), _) => false,
785        }
786    }
787}
788
789impl Eq for Val {}
790
791struct GenericVariant<'a> {
792    discriminant: u32,
793    payload: Option<(&'a Val, InterfaceType)>,
794    abi: &'a CanonicalAbiInfo,
795    info: &'a VariantInfo,
796}
797
798impl GenericVariant<'_> {
799    fn result<'a>(
800        ty: &'a TypeResult,
801        r: &'a Result<Option<Box<Val>>, Option<Box<Val>>>,
802    ) -> Result<GenericVariant<'a>> {
803        let (discriminant, payload) = match r {
804            Ok(val) => {
805                let payload = match (val, ty.ok) {
806                    (Some(val), Some(ty)) => Some((&**val, ty)),
807                    (None, None) => None,
808                    (Some(_), None) => {
809                        bail!("payload provided to `ok` but not expected");
810                    }
811                    (None, Some(_)) => {
812                        bail!("payload expected to `ok` but not provided");
813                    }
814                };
815                (0, payload)
816            }
817            Err(val) => {
818                let payload = match (val, ty.err) {
819                    (Some(val), Some(ty)) => Some((&**val, ty)),
820                    (None, None) => None,
821                    (Some(_), None) => {
822                        bail!("payload provided to `err` but not expected");
823                    }
824                    (None, Some(_)) => {
825                        bail!("payload expected to `err` but not provided");
826                    }
827                };
828                (1, payload)
829            }
830        };
831        Ok(GenericVariant {
832            discriminant,
833            payload,
834            abi: &ty.abi,
835            info: &ty.info,
836        })
837    }
838
839    fn option<'a>(ty: &'a TypeOption, r: &'a Option<Box<Val>>) -> GenericVariant<'a> {
840        let (discriminant, payload) = match r {
841            None => (0, None),
842            Some(val) => (1, Some((&**val, ty.ty))),
843        };
844        GenericVariant {
845            discriminant,
846            payload,
847            abi: &ty.abi,
848            info: &ty.info,
849        }
850    }
851
852    fn enum_<'a>(ty: &'a TypeEnum, discriminant: &str) -> Result<GenericVariant<'a>> {
853        let discriminant = get_enum_discriminant(ty, discriminant)?;
854
855        Ok(GenericVariant {
856            discriminant,
857            payload: None,
858            abi: &ty.abi,
859            info: &ty.info,
860        })
861    }
862
863    fn variant<'a>(
864        ty: &'a TypeVariant,
865        discriminant_name: &str,
866        payload: &'a Option<Box<Val>>,
867    ) -> Result<GenericVariant<'a>> {
868        let (discriminant, payload_ty) = get_variant_discriminant(ty, discriminant_name)?;
869
870        let payload = match (payload, payload_ty) {
871            (Some(val), Some(ty)) => Some((&**val, *ty)),
872            (None, None) => None,
873            (Some(_), None) => bail!("did not expect a payload for case `{discriminant_name}`"),
874            (None, Some(_)) => bail!("expected a payload for case `{discriminant_name}`"),
875        };
876
877        Ok(GenericVariant {
878            discriminant,
879            payload,
880            abi: &ty.abi,
881            info: &ty.info,
882        })
883    }
884
885    fn lower<T>(
886        &self,
887        cx: &mut LowerContext<'_, T>,
888        dst: &mut IterMut<'_, MaybeUninit<ValRaw>>,
889    ) -> Result<()> {
890        next_mut(dst).write(ValRaw::u32(self.discriminant));
891
892        // For the remaining lowered representation of this variant that
893        // the payload didn't write we write out zeros here to ensure
894        // the entire variant is written.
895        let value_flat = match self.payload {
896            Some((value, ty)) => {
897                value.lower(cx, ty, dst)?;
898                cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap()
899            }
900            None => 0,
901        };
902        let variant_flat = self.abi.flat_count(usize::MAX).unwrap();
903        for _ in (1 + value_flat)..variant_flat {
904            next_mut(dst).write(ValRaw::u64(0));
905        }
906        Ok(())
907    }
908
909    fn store<T>(&self, cx: &mut LowerContext<'_, T>, offset: usize) -> Result<()> {
910        match self.info.size {
911            DiscriminantSize::Size1 => u8::try_from(self.discriminant)
912                .unwrap()
913                .linear_lower_to_memory(cx, InterfaceType::U8, offset)?,
914            DiscriminantSize::Size2 => u16::try_from(self.discriminant)
915                .unwrap()
916                .linear_lower_to_memory(cx, InterfaceType::U16, offset)?,
917            DiscriminantSize::Size4 => {
918                self.discriminant
919                    .linear_lower_to_memory(cx, InterfaceType::U32, offset)?
920            }
921        }
922
923        if let Some((value, ty)) = self.payload {
924            let offset = offset + usize::try_from(self.info.payload_offset32).unwrap();
925            value.store(cx, ty, offset)?;
926        }
927
928        Ok(())
929    }
930}
931
932fn load_list(cx: &mut LiftContext<'_>, ty: TypeListIndex, ptr: usize, len: usize) -> Result<Val> {
933    let elem = cx.types[ty].element;
934    let abi = cx.types.canonical_abi(&elem);
935    let element_size = usize::try_from(abi.size32).unwrap();
936    let element_alignment = abi.align32;
937
938    match len
939        .checked_mul(element_size)
940        .and_then(|len| ptr.checked_add(len))
941    {
942        Some(n) if n <= cx.memory().len() => {}
943        _ => bail!("list pointer/length out of bounds of memory"),
944    }
945    if ptr % usize::try_from(element_alignment)? != 0 {
946        bail!("list pointer is not aligned")
947    }
948
949    Ok(Val::List(
950        (0..len)
951            .map(|index| {
952                Val::load(
953                    cx,
954                    elem,
955                    &cx.memory()[ptr + (index * element_size)..][..element_size],
956                )
957            })
958            .collect::<Result<_>>()?,
959    ))
960}
961
962fn load_variant(
963    cx: &mut LiftContext<'_>,
964    info: &VariantInfo,
965    mut types: impl ExactSizeIterator<Item = Option<InterfaceType>>,
966    bytes: &[u8],
967) -> Result<(u32, Option<Box<Val>>)> {
968    let discriminant = match info.size {
969        DiscriminantSize::Size1 => u32::from(u8::linear_lift_from_memory(
970            cx,
971            InterfaceType::U8,
972            &bytes[..1],
973        )?),
974        DiscriminantSize::Size2 => u32::from(u16::linear_lift_from_memory(
975            cx,
976            InterfaceType::U16,
977            &bytes[..2],
978        )?),
979        DiscriminantSize::Size4 => {
980            u32::linear_lift_from_memory(cx, InterfaceType::U32, &bytes[..4])?
981        }
982    };
983    let case_ty = types.nth(discriminant as usize).ok_or_else(|| {
984        anyhow!(
985            "discriminant {} out of range [0..{})",
986            discriminant,
987            types.len()
988        )
989    })?;
990    let value = match case_ty {
991        Some(case_ty) => {
992            let payload_offset = usize::try_from(info.payload_offset32).unwrap();
993            let case_abi = cx.types.canonical_abi(&case_ty);
994            let case_size = usize::try_from(case_abi.size32).unwrap();
995            Some(Box::new(Val::load(
996                cx,
997                case_ty,
998                &bytes[payload_offset..][..case_size],
999            )?))
1000        }
1001        None => None,
1002    };
1003    Ok((discriminant, value))
1004}
1005
1006fn lift_variant(
1007    cx: &mut LiftContext<'_>,
1008    flatten_count: usize,
1009    mut types: impl ExactSizeIterator<Item = Option<InterfaceType>>,
1010    src: &mut Iter<'_, ValRaw>,
1011) -> Result<(u32, Option<Box<Val>>)> {
1012    let len = types.len();
1013    let discriminant = next(src).get_u32();
1014    let ty = types
1015        .nth(discriminant as usize)
1016        .ok_or_else(|| anyhow!("discriminant {} out of range [0..{})", discriminant, len))?;
1017    let (value, value_flat) = match ty {
1018        Some(ty) => (
1019            Some(Box::new(Val::lift(cx, ty, src)?)),
1020            cx.types.canonical_abi(&ty).flat_count(usize::MAX).unwrap(),
1021        ),
1022        None => (None, 0),
1023    };
1024    for _ in (1 + value_flat)..flatten_count {
1025        next(src);
1026    }
1027    Ok((discriminant, value))
1028}
1029
1030/// Lower a list with the specified element type and values.
1031fn lower_list<T>(
1032    cx: &mut LowerContext<'_, T>,
1033    element_type: InterfaceType,
1034    items: &[Val],
1035) -> Result<(usize, usize)> {
1036    let abi = cx.types.canonical_abi(&element_type);
1037    let elt_size = usize::try_from(abi.size32)?;
1038    let elt_align = abi.align32;
1039    let size = items
1040        .len()
1041        .checked_mul(elt_size)
1042        .ok_or_else(|| anyhow::anyhow!("size overflow copying a list"))?;
1043    let ptr = cx.realloc(0, 0, elt_align, size)?;
1044    let mut element_ptr = ptr;
1045    for item in items {
1046        item.store(cx, element_type, element_ptr)?;
1047        element_ptr += elt_size;
1048    }
1049    Ok((ptr, items.len()))
1050}
1051
1052fn push_flags(ty: &TypeFlags, flags: &mut Vec<String>, mut offset: u32, mut bits: u32) {
1053    while bits > 0 {
1054        if bits & 1 != 0 {
1055            flags.push(ty.names[offset as usize].clone());
1056        }
1057        bits >>= 1;
1058        offset += 1;
1059    }
1060}
1061
1062fn flags_to_storage(ty: &TypeFlags, flags: &[String]) -> Result<Vec<u32>> {
1063    let mut storage = match FlagsSize::from_count(ty.names.len()) {
1064        FlagsSize::Size0 => Vec::new(),
1065        FlagsSize::Size1 | FlagsSize::Size2 => vec![0],
1066        FlagsSize::Size4Plus(n) => vec![0; n.into()],
1067    };
1068
1069    for flag in flags {
1070        let bit = ty
1071            .names
1072            .get_index_of(flag)
1073            .ok_or_else(|| anyhow::anyhow!("unknown flag: `{flag}`"))?;
1074        storage[bit / 32] |= 1 << (bit % 32);
1075    }
1076    Ok(storage)
1077}
1078
1079fn get_enum_discriminant(ty: &TypeEnum, n: &str) -> Result<u32> {
1080    ty.names
1081        .get_index_of(n)
1082        .ok_or_else(|| anyhow::anyhow!("enum variant name `{n}` is not valid"))
1083        .map(|i| i.try_into().unwrap())
1084}
1085
1086fn get_variant_discriminant<'a>(
1087    ty: &'a TypeVariant,
1088    name: &str,
1089) -> Result<(u32, &'a Option<InterfaceType>)> {
1090    let (i, _, ty) = ty
1091        .cases
1092        .get_full(name)
1093        .ok_or_else(|| anyhow::anyhow!("unknown variant case: `{name}`"))?;
1094    Ok((i.try_into().unwrap(), ty))
1095}
1096
1097fn next<'a>(src: &mut Iter<'a, ValRaw>) -> &'a ValRaw {
1098    src.next().unwrap()
1099}
1100
1101fn next_mut<'a>(dst: &mut IterMut<'a, MaybeUninit<ValRaw>>) -> &'a mut MaybeUninit<ValRaw> {
1102    dst.next().unwrap()
1103}
1104
1105#[cold]
1106fn unexpected<T>(ty: InterfaceType, val: &Val) -> Result<T> {
1107    bail!(
1108        "type mismatch: expected {}, found {}",
1109        desc(&ty),
1110        val.desc()
1111    )
1112}
1113
1114/// Represents a component model `future`.
1115///
1116/// Note that this type is not usable at this time as its implementation has not
1117/// been filled out. There are no operations on this and there's additionally no
1118/// ability to "drop" or deallocate this index. This means that from the
1119/// perspective of wasm it'll appear that this handle has "leaked" without ever
1120/// being dropped or read from.
1121//
1122// FIXME(#11161) this needs to be filled out implementation-wise
1123#[derive(Debug, Clone, PartialEq, Eq)]
1124pub struct FutureAny(pub(crate) u32);
1125
1126/// Represents a component model `stream`.
1127///
1128/// Note that this type is not usable at this time as its implementation has not
1129/// been filled out. There are no operations on this and there's additionally no
1130/// ability to "drop" or deallocate this index. This means that from the
1131/// perspective of wasm it'll appear that this handle has "leaked" without ever
1132/// being dropped or read from.
1133//
1134// FIXME(#11161) this needs to be filled out implementation-wise
1135#[derive(Debug, Clone, PartialEq, Eq)]
1136pub struct StreamAny(pub(crate) u32);
1137
1138/// Represents a component model `error-context`.
1139///
1140/// Note that this type is not usable at this time as its implementation has not
1141/// been filled out. There are no operations on this and there's additionally no
1142/// ability to "drop" or deallocate this index.
1143//
1144// FIXME(#11161) this needs to be filled out implementation-wise
1145#[derive(Debug, Clone, PartialEq, Eq)]
1146pub struct ErrorContextAny(pub(crate) u32);