Skip to main content

wasmtime/runtime/component/func/
typed.rs

1use crate::component::Instance;
2use crate::component::func::{Func, LiftContext, LowerContext};
3use crate::component::matching::InstanceType;
4use crate::component::storage::{storage_as_slice, storage_as_slice_mut};
5use crate::hash_map::HashMap;
6use crate::prelude::*;
7use crate::{AsContextMut, StoreContext, StoreContextMut, ValRaw};
8use alloc::borrow::Cow;
9use core::fmt;
10use core::hash::Hash;
11use core::iter;
12use core::marker;
13use core::mem::{self, MaybeUninit};
14use core::str;
15use wasmtime_core::array::array_try_from_fn;
16use wasmtime_environ::component::{
17    CanonicalAbiInfo, ComponentTypes, InterfaceType, MAX_FLAT_PARAMS, MAX_FLAT_RESULTS,
18    OptionsIndex, StringEncoding, TypeMap, VariantInfo,
19};
20
21/// A statically-typed version of [`Func`] which takes `Params` as input and
22/// returns `Return`.
23///
24/// This is an efficient way to invoke a WebAssembly component where if the
25/// inputs and output are statically known this can eschew the vast majority of
26/// machinery and checks when calling WebAssembly. This is the most optimized
27/// way to call a WebAssembly component.
28///
29/// Note that like [`Func`] this is a pointer within a [`Store`](crate::Store)
30/// and usage will panic if used with the wrong store.
31///
32/// This type is primarily created with the [`Func::typed`] API.
33///
34/// See [`ComponentType`] for more information about supported types.
35pub struct TypedFunc<Params, Return> {
36    func: Func,
37
38    // The definition of this field is somewhat subtle and may be surprising.
39    // Naively one might expect something like
40    //
41    //      _marker: marker::PhantomData<fn(Params) -> Return>,
42    //
43    // Since this is a function pointer after all. The problem with this
44    // definition though is that it imposes the wrong variance on `Params` from
45    // what we want. Abstractly a `fn(Params)` is able to store `Params` within
46    // it meaning you can only give it `Params` that live longer than the
47    // function pointer.
48    //
49    // With a component model function, however, we're always copying data from
50    // the host into the guest, so we are never storing pointers to `Params`
51    // into the guest outside the duration of a `call`, meaning we can actually
52    // accept values in `TypedFunc::call` which live for a shorter duration
53    // than the `Params` argument on the struct.
54    //
55    // This all means that we don't use a phantom function pointer, but instead
56    // feign phantom storage here to get the variance desired.
57    _marker: marker::PhantomData<(Params, Return)>,
58}
59
60impl<Params, Return> Copy for TypedFunc<Params, Return> {}
61
62impl<Params, Return> Clone for TypedFunc<Params, Return> {
63    fn clone(&self) -> TypedFunc<Params, Return> {
64        *self
65    }
66}
67
68impl<Params, Return> TypedFunc<Params, Return>
69where
70    Params: ComponentNamedList + Lower,
71    Return: ComponentNamedList + Lift,
72{
73    /// Creates a new [`TypedFunc`] from the provided component [`Func`],
74    /// unsafely asserting that the underlying function takes `Params` as
75    /// input and returns `Return`.
76    ///
77    /// # Unsafety
78    ///
79    /// This is an unsafe function because it does not verify that the [`Func`]
80    /// provided actually implements this signature. It's up to the caller to
81    /// have performed some other sort of check to ensure that the signature is
82    /// correct.
83    pub unsafe fn new_unchecked(func: Func) -> TypedFunc<Params, Return> {
84        TypedFunc {
85            _marker: marker::PhantomData,
86            func,
87        }
88    }
89
90    /// Returns the underlying un-typed [`Func`] that this [`TypedFunc`]
91    /// references.
92    pub fn func(&self) -> &Func {
93        &self.func
94    }
95
96    /// Calls the underlying WebAssembly component function using the provided
97    /// `params` as input.
98    ///
99    /// This method is used to enter into a component. Execution happens within
100    /// the `store` provided. The `params` are copied into WebAssembly memory
101    /// as appropriate and a core wasm function is invoked.
102    ///
103    /// # Post-return
104    ///
105    /// In the component model each function can have a "post return" specified
106    /// which allows cleaning up the arguments returned to the host. For example
107    /// if WebAssembly returns a string to the host then it might be a uniquely
108    /// allocated string which, after the host finishes processing it, needs to
109    /// be deallocated in the wasm instance's own linear memory to prevent
110    /// memory leaks in wasm itself. The `post-return` canonical abi option is
111    /// used to configured this.
112    ///
113    /// If a post-return function is present, it will be called automatically by
114    /// this function.
115    ///
116    /// # Errors
117    ///
118    /// This function can return an error for a number of reasons:
119    ///
120    /// * If the wasm itself traps during execution.
121    /// * If the wasm traps while copying arguments into memory.
122    /// * If the wasm provides bad allocation pointers when copying arguments
123    ///   into memory.
124    /// * If the wasm returns a value which violates the canonical ABI.
125    /// * If this function's instances cannot be entered, for example if the
126    ///   instance is currently calling a host function.
127    /// * If `store` requires using [`Self::call_async`] instead, see
128    ///   [crate documentation](crate#async) for more info.
129    ///
130    /// In general there are many ways that things could go wrong when copying
131    /// types in and out of a wasm module with the canonical ABI, and certain
132    /// error conditions are specific to certain types. For example a
133    /// WebAssembly module can't return an invalid `char`. When allocating space
134    /// for this host to copy a string into the returned pointer must be
135    /// in-bounds in memory.
136    ///
137    /// If an error happens then the error should contain detailed enough
138    /// information to understand which part of the canonical ABI went wrong
139    /// and what to inspect.
140    ///
141    /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
142    /// memory allocation fails. See the `OutOfMemory` type's documentation for
143    /// details on Wasmtime's out-of-memory handling.
144    ///
145    /// # Panics
146    ///
147    /// Panics if `store` does not own this function.
148    pub fn call(&self, mut store: impl AsContextMut, params: Params) -> Result<Return> {
149        let mut store = store.as_context_mut();
150        store.0.validate_sync_call()?;
151        self.call_impl(store.as_context_mut(), params)
152    }
153
154    /// Exactly like [`Self::call`], except for invoking WebAssembly
155    /// [asynchronously](crate#async).
156    ///
157    /// # Errors
158    ///
159    /// This function will return an [`OutOfMemory`][crate::OutOfMemory] error when
160    /// memory allocation fails. See the `OutOfMemory` type's documentation for
161    /// details on Wasmtime's out-of-memory handling.
162    ///
163    /// # Panics
164    ///
165    /// Panics if `store` does not own this function.
166    #[cfg(feature = "async")]
167    pub async fn call_async(
168        &self,
169        mut store: impl AsContextMut<Data: Send>,
170        params: Params,
171    ) -> Result<Return>
172    where
173        Return: 'static,
174    {
175        let mut store = store.as_context_mut();
176
177        #[cfg(feature = "component-model-async")]
178        if store.0.concurrency_support() {
179            return self.call_async_concurrent(store, params).await;
180        }
181
182        store
183            .on_fiber(|store| self.call_impl(store, params))
184            .await?
185    }
186
187    pub(crate) fn lower_args<T>(
188        cx: &mut LowerContext<T>,
189        ty: InterfaceType,
190        dst: &mut [MaybeUninit<ValRaw>],
191        params: &Params,
192    ) -> Result<()> {
193        use crate::component::storage::slice_to_storage_mut;
194
195        if Params::flatten_count() <= MAX_FLAT_PARAMS {
196            // SAFETY: the safety of `slice_to_storage_mut` relies on
197            // `Params::Lower` being represented by a sequence of
198            // `ValRaw`, and that's a guarantee upheld by the `Lower`
199            // trait itself.
200            let dst: &mut MaybeUninit<Params::Lower> = unsafe { slice_to_storage_mut(dst) };
201            Self::lower_stack_args(cx, &params, ty, dst)
202        } else {
203            Self::lower_heap_args(cx, &params, ty, &mut dst[0])
204        }
205    }
206
207    fn call_impl(&self, mut store: impl AsContextMut, params: Params) -> Result<Return> {
208        let mut store = store.as_context_mut();
209
210        if self.func.abi_async(store.0) {
211            bail!("must enable the `component-model-async` feature to call async-lifted exports")
212        }
213
214        // Note that this is in theory simpler than it might read at this time.
215        // Here we're doing a runtime dispatch on the `flatten_count` for the
216        // params/results to see whether they're inbounds. This creates 4 cases
217        // to handle. In reality this is a highly optimizable branch where LLVM
218        // will easily figure out that only one branch here is taken.
219        //
220        // Otherwise this current construction is done to ensure that the stack
221        // space reserved for the params/results is always of the appropriate
222        // size (as the params/results needed differ depending on the "flatten"
223        // count)
224        //
225        // SAFETY: the safety of these invocations of `call_raw` depends on the
226        // correctness of the ascription of the `LowerParams` and `LowerReturn`
227        // types on the `call_raw` function. That's upheld here through the
228        // safety requirements of `Lift` and `Lower` on `Params` and `Return` in
229        // combination with checking the various possible branches here and
230        // dispatching to appropriately typed functions.
231        let result = unsafe {
232            // This type is used as `LowerParams` for `call_raw` which is either
233            // `Params::Lower` or `ValRaw` representing it's either on the stack
234            // or it's on the heap. This allocates 1 extra `ValRaw` on the stack
235            // if `Params` is empty and `Return` is also empty, but that's a
236            // reasonable enough price to pay for now given the current code
237            // organization.
238            #[derive(Copy, Clone)]
239            union Union<T: Copy, U: Copy> {
240                _a: T,
241                _b: U,
242            }
243
244            if Return::flatten_count() <= MAX_FLAT_RESULTS {
245                self.func.call_raw(
246                    store.as_context_mut(),
247                    |cx, ty, dst: &mut MaybeUninit<Union<Params::Lower, ValRaw>>| {
248                        let dst = storage_as_slice_mut(dst);
249                        Self::lower_args(cx, ty, dst, &params)
250                    },
251                    Self::lift_stack_result,
252                )
253            } else {
254                self.func.call_raw(
255                    store.as_context_mut(),
256                    |cx, ty, dst: &mut MaybeUninit<Union<Params::Lower, ValRaw>>| {
257                        let dst = storage_as_slice_mut(dst);
258                        Self::lower_args(cx, ty, dst, &params)
259                    },
260                    Self::lift_heap_result,
261                )
262            }
263        };
264
265        if result.is_err() {
266            store.0.set_trapped();
267        }
268
269        result
270    }
271
272    /// Lower parameters directly onto the stack specified by the `dst`
273    /// location.
274    ///
275    /// This is only valid to call when the "flatten count" is small enough, or
276    /// when the canonical ABI says arguments go through the stack rather than
277    /// the heap.
278    fn lower_stack_args<T>(
279        cx: &mut LowerContext<'_, T>,
280        params: &Params,
281        ty: InterfaceType,
282        dst: &mut MaybeUninit<Params::Lower>,
283    ) -> Result<()> {
284        assert!(Params::flatten_count() <= MAX_FLAT_PARAMS);
285        params.linear_lower_to_flat(cx, ty, dst)?;
286        Ok(())
287    }
288
289    /// Lower parameters onto a heap-allocated location.
290    ///
291    /// This is used when the stack space to be used for the arguments is above
292    /// the `MAX_FLAT_PARAMS` threshold. Here the wasm's `realloc` function is
293    /// invoked to allocate space and then parameters are stored at that heap
294    /// pointer location.
295    fn lower_heap_args<T>(
296        cx: &mut LowerContext<'_, T>,
297        params: &Params,
298        ty: InterfaceType,
299        dst: &mut MaybeUninit<ValRaw>,
300    ) -> Result<()> {
301        // Memory must exist via validation if the arguments are stored on the
302        // heap, so we can create a `MemoryMut` at this point. Afterwards
303        // `realloc` is used to allocate space for all the arguments and then
304        // they're all stored in linear memory.
305        //
306        // Note that `realloc` will bake in a check that the returned pointer is
307        // in-bounds.
308        let ptr = cx.realloc(0, 0, Params::ALIGN32, Params::SIZE32)?;
309        params.linear_lower_to_memory(cx, ty, ptr)?;
310
311        // Note that the pointer here is stored as a 64-bit integer. This allows
312        // this to work with either 32 or 64-bit memories. For a 32-bit memory
313        // it'll just ignore the upper 32 zero bits, and for 64-bit memories
314        // this'll have the full 64-bits. Note that for 32-bit memories the call
315        // to `realloc` above guarantees that the `ptr` is in-bounds meaning
316        // that we will know that the zero-extended upper bits of `ptr` are
317        // guaranteed to be zero.
318        //
319        // This comment about 64-bit integers is also referred to below with
320        // "WRITEPTR64".
321        dst.write(ValRaw::i64(ptr as i64));
322
323        Ok(())
324    }
325
326    /// Lift the result of a function directly from the stack result.
327    ///
328    /// This is only used when the result fits in the maximum number of stack
329    /// slots.
330    pub(crate) fn lift_stack_result(
331        cx: &mut LiftContext<'_>,
332        ty: InterfaceType,
333        dst: &Return::Lower,
334    ) -> Result<Return> {
335        Return::linear_lift_from_flat(cx, ty, dst)
336    }
337
338    /// Lift the result of a function where the result is stored indirectly on
339    /// the heap.
340    pub(crate) fn lift_heap_result(
341        cx: &mut LiftContext<'_>,
342        ty: InterfaceType,
343        dst: &ValRaw,
344    ) -> Result<Return> {
345        assert!(Return::flatten_count() > MAX_FLAT_RESULTS);
346        // FIXME(#4311): needs to read an i64 for memory64
347        let ptr = usize::try_from(dst.get_u32())?;
348        if ptr % usize::try_from(Return::ALIGN32)? != 0 {
349            bail!("return pointer not aligned");
350        }
351
352        let bytes = cx
353            .memory()
354            .get(ptr..)
355            .and_then(|b| b.get(..Return::SIZE32))
356            .ok_or_else(|| crate::format_err!("pointer out of bounds of memory"))?;
357        Return::linear_lift_from_memory(cx, ty, bytes)
358    }
359
360    #[doc(hidden)]
361    #[deprecated(note = "no longer needs to be called; this function has no effect")]
362    pub fn post_return(&self, _store: impl AsContextMut) -> Result<()> {
363        Ok(())
364    }
365
366    #[doc(hidden)]
367    #[deprecated(note = "no longer needs to be called; this function has no effect")]
368    #[cfg(feature = "async")]
369    pub async fn post_return_async<T: Send>(
370        &self,
371        _store: impl AsContextMut<Data = T>,
372    ) -> Result<()> {
373        Ok(())
374    }
375}
376
377/// A trait representing a static list of named types that can be passed to or
378/// returned from a [`TypedFunc`].
379///
380/// This trait is implemented for a number of tuple types and is not expected
381/// to be implemented externally. The contents of this trait are hidden as it's
382/// intended to be an implementation detail of Wasmtime. The contents of this
383/// trait are not covered by Wasmtime's stability guarantees.
384///
385/// For more information about this trait see [`Func::typed`] and
386/// [`TypedFunc`].
387//
388// Note that this is an `unsafe` trait, and the unsafety means that
389// implementations of this trait must be correct or otherwise [`TypedFunc`]
390// would not be memory safe. The main reason this is `unsafe` is the
391// `typecheck` function which must operate correctly relative to the `AsTuple`
392// interpretation of the implementor.
393pub unsafe trait ComponentNamedList: ComponentType {}
394
395/// A trait representing types which can be passed to and read from components
396/// with the canonical ABI.
397///
398/// This trait is implemented for Rust types which can be communicated to
399/// components. The [`Func::typed`] and [`TypedFunc`] Rust items are the main
400/// consumers of this trait.
401///
402/// Supported Rust types include:
403///
404/// | Component Model Type              | Rust Type                            |
405/// |-----------------------------------|--------------------------------------|
406/// | `{s,u}{8,16,32,64}`               | `{i,u}{8,16,32,64}`                  |
407/// | `f{32,64}`                        | `f{32,64}`                           |
408/// | `bool`                            | `bool`                               |
409/// | `char`                            | `char`                               |
410/// | `tuple<A, B>`                     | `(A, B)`                             |
411/// | `option<T>`                       | `Option<T>`                          |
412/// | `result`                          | `Result<(), ()>`                     |
413/// | `result<T>`                       | `Result<T, ()>`                      |
414/// | `result<_, E>`                    | `Result<(), E>`                      |
415/// | `result<T, E>`                    | `Result<T, E>`                       |
416/// | `string`                          | `String`, `&str`, or [`WasmStr`]     |
417/// | `list<T>`                         | `Vec<T>`, `&[T]`, or [`WasmList`]    |
418/// | `map<K, V>`                       | `HashMap<K, V>`                      |
419/// | `own<T>`, `borrow<T>`             | [`Resource<T>`] or [`ResourceAny`]   |
420/// | `record`                          | [`#[derive(ComponentType)]`][d-cm]   |
421/// | `variant`                         | [`#[derive(ComponentType)]`][d-cm]   |
422/// | `enum`                            | [`#[derive(ComponentType)]`][d-cm]   |
423/// | `flags`                           | [`flags!`][f-m]                      |
424///
425/// [`Resource<T>`]: crate::component::Resource
426/// [`ResourceAny`]: crate::component::ResourceAny
427/// [d-cm]: macro@crate::component::ComponentType
428/// [f-m]: crate::component::flags
429///
430/// Rust standard library pointers such as `&T`, `Box<T>`, and `Arc<T>`
431/// additionally represent whatever type `T` represents in the component model.
432/// Note that types such as `record`, `variant`, `enum`, and `flags` are
433/// generated by the embedder at compile time. These macros derive
434/// implementation of this trait for custom types to map to custom types in the
435/// component model. Note that for `record`, `variant`, `enum`, and `flags`
436/// those types are often generated by the
437/// [`bindgen!`](crate::component::bindgen) macro from WIT definitions.
438///
439/// Types that implement [`ComponentType`] are used for `Params` and `Return`
440/// in [`TypedFunc`] and [`Func::typed`].
441///
442/// The contents of this trait are hidden as it's intended to be an
443/// implementation detail of Wasmtime. The contents of this trait are not
444/// covered by Wasmtime's stability guarantees.
445///
446/// # Safety
447///
448/// Note that this is an `unsafe` trait as `TypedFunc`'s safety heavily relies on
449/// the correctness of the implementations of this trait. Some ways in which this
450/// trait must be correct to be safe are:
451///
452/// * The `Lower` associated type must be a `ValRaw` sequence. It doesn't have to
453///   literally be `[ValRaw; N]` but when laid out in memory it must be adjacent
454///   `ValRaw` values and have a multiple of the size of `ValRaw` and the same
455///   alignment.
456///
457/// * The `lower` function must initialize the bits within `Lower` that are going
458///   to be read by the trampoline that's used to enter core wasm. A trampoline
459///   is passed `*mut Lower` and will read the canonical abi arguments in
460///   sequence, so all of the bits must be correctly initialized.
461///
462/// * The `size` and `align` functions must be correct for this value stored in
463///   the canonical ABI. The `Cursor<T>` iteration of these bytes rely on this
464///   for correctness as they otherwise eschew bounds-checking.
465///
466/// There are likely some other correctness issues which aren't documented as
467/// well, this isn't currently an exhaustive list. It suffices to say, though,
468/// that correctness bugs in this trait implementation are highly likely to
469/// lead to security bugs, which again leads to the `unsafe` in the trait.
470///
471/// Note that this trait specifically is not sealed because `bindgen!`-generated
472/// types must be able to implement this trait using a `#[derive]` macro. For
473/// users it's recommended to not implement this trait manually given the
474/// non-exhaustive list of safety requirements that must be upheld. This trait
475/// is implemented at your own risk if you do so.
476///
477/// # Send and Sync
478///
479/// While on the topic of safety it's worth discussing the `Send` and `Sync`
480/// bounds here as well. These bounds might naively seem like they shouldn't be
481/// required for all component types as they're host-level types not guest-level
482/// types persisted anywhere. Various subtleties lead to these bounds, however:
483///
484/// * Fibers require that all stack-local variables are `Send` and `Sync` for
485///   fibers themselves to be send/sync. Unfortunately we have no help from the
486///   compiler on this one so it's up to Wasmtime's discipline to maintain this.
487///   One instance of this is that return values are placed on the stack as
488///   they're lowered into guest memory. This lowering operation can involve
489///   malloc and context switches, so return values must be Send/Sync.
490///
491/// * In the implementation of component model async it's not uncommon for types
492///   to be "buffered" in the store temporarily. For example parameters might
493///   reside in a store temporarily while wasm has backpressure turned on.
494///
495/// Overall it's generally easiest to require `Send` and `Sync` for all
496/// component types. There additionally aren't known use case for non-`Send` or
497/// non-`Sync` types at this time.
498pub unsafe trait ComponentType: Send + Sync {
499    /// Representation of the "lowered" form of this component value.
500    ///
501    /// Lowerings lower into core wasm values which are represented by `ValRaw`.
502    /// This `Lower` type must be a list of `ValRaw` as either a literal array
503    /// or a struct where every field is a `ValRaw`. This must be `Copy` (as
504    /// `ValRaw` is `Copy`) and support all byte patterns. This being correct is
505    /// one reason why the trait is unsafe.
506    #[doc(hidden)]
507    type Lower: Copy;
508
509    /// The information about this type's canonical ABI (size/align/etc).
510    #[doc(hidden)]
511    const ABI: CanonicalAbiInfo;
512
513    #[doc(hidden)]
514    const SIZE32: usize = Self::ABI.size32 as usize;
515    #[doc(hidden)]
516    const ALIGN32: u32 = Self::ABI.align32;
517
518    #[doc(hidden)]
519    const IS_RUST_UNIT_TYPE: bool = false;
520
521    /// Whether this type might require a call to the guest's realloc function
522    /// to allocate linear memory when lowering (e.g. a non-empty `string`).
523    ///
524    /// If this is `false`, Wasmtime may optimize lowering by using
525    /// `LowerContext::new_without_realloc` and lowering values outside of any
526    /// fiber.  That will panic if the lowering process ends up needing realloc
527    /// after all, so `true` is a conservative default.
528    #[doc(hidden)]
529    const MAY_REQUIRE_REALLOC: bool = true;
530
531    /// Returns the number of core wasm abi values will be used to represent
532    /// this type in its lowered form.
533    ///
534    /// This divides the size of `Self::Lower` by the size of `ValRaw`.
535    #[doc(hidden)]
536    fn flatten_count() -> usize {
537        assert!(mem::size_of::<Self::Lower>() % mem::size_of::<ValRaw>() == 0);
538        assert!(mem::align_of::<Self::Lower>() == mem::align_of::<ValRaw>());
539        mem::size_of::<Self::Lower>() / mem::size_of::<ValRaw>()
540    }
541
542    /// Performs a type-check to see whether this component value type matches
543    /// the interface type `ty` provided.
544    #[doc(hidden)]
545    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()>;
546}
547
548#[doc(hidden)]
549pub unsafe trait ComponentVariant: ComponentType {
550    const CASES: &'static [Option<CanonicalAbiInfo>];
551    const INFO: VariantInfo = VariantInfo::new_static(Self::CASES);
552    const PAYLOAD_OFFSET32: usize = Self::INFO.payload_offset32 as usize;
553}
554
555/// Host types which can be passed to WebAssembly components.
556///
557/// This trait is implemented for all types that can be passed to components
558/// either as parameters of component exports or returns of component imports.
559/// This trait represents the ability to convert from the native host
560/// representation to the canonical ABI.
561///
562/// Built-in types to Rust such as `Option<T>` implement this trait as
563/// appropriate. For a mapping of component model to Rust types see
564/// [`ComponentType`].
565///
566/// For user-defined types, for example `record` types mapped to Rust `struct`s,
567/// this crate additionally has
568/// [`#[derive(Lower)]`](macro@crate::component::Lower).
569///
570/// Note that like [`ComponentType`] the definition of this trait is intended to
571/// be an internal implementation detail of Wasmtime at this time. It's
572/// recommended to use the `#[derive(Lower)]` implementation instead.
573pub unsafe trait Lower: ComponentType {
574    /// Performs the "lower" function in the linear memory version of the
575    /// canonical ABI.
576    ///
577    /// This method will lower the current value into a component. The `lower`
578    /// function performs a "flat" lowering into the `dst` specified which is
579    /// allowed to be uninitialized entering this method but is guaranteed to be
580    /// fully initialized if the method returns `Ok(())`.
581    ///
582    /// The `cx` context provided is the context within which this lowering is
583    /// happening. This contains information such as canonical options specified
584    /// (e.g. string encodings, memories, etc), the store itself, along with
585    /// type information.
586    ///
587    /// The `ty` parameter is the destination type that is being lowered into.
588    /// For example this is the component's "view" of the type that is being
589    /// lowered. This is guaranteed to have passed a `typecheck` earlier.
590    ///
591    /// This will only be called if `typecheck` passes for `Op::Lower`.
592    #[doc(hidden)]
593    fn linear_lower_to_flat<T>(
594        &self,
595        cx: &mut LowerContext<'_, T>,
596        ty: InterfaceType,
597        dst: &mut MaybeUninit<Self::Lower>,
598    ) -> Result<()>;
599
600    /// Performs the "store" operation in the linear memory version of the
601    /// canonical ABI.
602    ///
603    /// This function will store `self` into the linear memory described by
604    /// `cx` at the `offset` provided.
605    ///
606    /// It is expected that `offset` is a valid offset in memory for
607    /// `Self::SIZE32` bytes. At this time that's not an unsafe contract as it's
608    /// always re-checked on all stores, but this is something that will need to
609    /// be improved in the future to remove extra bounds checks. For now this
610    /// function will panic if there's a bug and `offset` isn't valid within
611    /// memory.
612    ///
613    /// The `ty` type information passed here is the same as the type
614    /// information passed to `lower` above, and is the component's own view of
615    /// what the resulting type should be.
616    ///
617    /// This will only be called if `typecheck` passes for `Op::Lower`.
618    #[doc(hidden)]
619    fn linear_lower_to_memory<T>(
620        &self,
621        cx: &mut LowerContext<'_, T>,
622        ty: InterfaceType,
623        offset: usize,
624    ) -> Result<()>;
625
626    /// Provided method to lower a list of `Self` into memory.
627    ///
628    /// Requires that `offset` has already been checked for alignment and
629    /// validity in terms of being in-bounds, otherwise this may panic.
630    ///
631    /// This is primarily here to get overridden for implementations of integers
632    /// which can avoid some extra fluff and use a pattern that's more easily
633    /// optimizable by LLVM.
634    #[doc(hidden)]
635    fn linear_store_list_to_memory<T>(
636        cx: &mut LowerContext<'_, T>,
637        ty: InterfaceType,
638        mut offset: usize,
639        items: &[Self],
640    ) -> Result<()>
641    where
642        Self: Sized,
643    {
644        for item in items {
645            item.linear_lower_to_memory(cx, ty, offset)?;
646            offset += Self::SIZE32;
647        }
648        Ok(())
649    }
650}
651
652/// Host types which can be created from the canonical ABI.
653///
654/// This is the mirror of the [`Lower`] trait where it represents the capability
655/// of acquiring items from WebAssembly and passing them to the host.
656///
657/// Built-in types to Rust such as `Option<T>` implement this trait as
658/// appropriate. For a mapping of component model to Rust types see
659/// [`ComponentType`].
660///
661/// For user-defined types, for example `record` types mapped to Rust `struct`s,
662/// this crate additionally has
663/// [`#[derive(Lift)]`](macro@crate::component::Lift).
664///
665/// Note that like [`ComponentType`] the definition of this trait is intended to
666/// be an internal implementation detail of Wasmtime at this time. It's
667/// recommended to use the `#[derive(Lift)]` implementation instead.
668pub unsafe trait Lift: Sized + ComponentType {
669    /// Performs the "lift" operation in the linear memory version of the
670    /// canonical ABI.
671    ///
672    /// This function performs a "flat" lift operation from the `src` specified
673    /// which is a sequence of core wasm values. The lifting operation will
674    /// validate core wasm values and produce a `Self` on success.
675    ///
676    /// The `cx` provided contains contextual information such as the store
677    /// that's being loaded from, canonical options, and type information.
678    ///
679    /// The `ty` parameter is the origin component's specification for what the
680    /// type that is being lifted is. For example this is the record type or the
681    /// resource type that is being lifted.
682    ///
683    /// Note that this has a default implementation but if `typecheck` passes
684    /// for `Op::Lift` this needs to be overridden.
685    #[doc(hidden)]
686    fn linear_lift_from_flat(
687        cx: &mut LiftContext<'_>,
688        ty: InterfaceType,
689        src: &Self::Lower,
690    ) -> Result<Self>;
691
692    /// Performs the "load" operation in the linear memory version of the
693    /// canonical ABI.
694    ///
695    /// This will read the `bytes` provided, which are a sub-slice into the
696    /// linear memory described by `cx`. The `bytes` array provided is
697    /// guaranteed to be `Self::SIZE32` bytes large. All of memory is then also
698    /// available through `cx` for bounds-checks and such as necessary for
699    /// strings/lists.
700    ///
701    /// The `ty` argument is the type that's being loaded, as described by the
702    /// original component.
703    ///
704    /// Note that this has a default implementation but if `typecheck` passes
705    /// for `Op::Lift` this needs to be overridden.
706    #[doc(hidden)]
707    fn linear_lift_from_memory(
708        cx: &mut LiftContext<'_>,
709        ty: InterfaceType,
710        bytes: &[u8],
711    ) -> Result<Self>;
712
713    /// Converts `list` into a `Vec<T>`, used in `Lift for Vec<T>`.
714    #[doc(hidden)]
715    fn linear_lift_list_from_memory(
716        cx: &mut LiftContext<'_>,
717        list: &WasmList<Self>,
718    ) -> Result<Vec<Self>>
719    where
720        Self: Sized,
721    {
722        let mut dst = Vec::with_capacity(list.len);
723        Self::linear_lift_into_from_memory(cx, list, &mut dst)?;
724        Ok(dst)
725    }
726
727    /// Load no more than `max_count` items from `list` into `dst`.
728    ///
729    /// This is primarily here to get overridden for implementations of integers
730    /// which can avoid some extra fluff and use a pattern that's more easily
731    /// optimizable by LLVM.
732    #[doc(hidden)]
733    fn linear_lift_into_from_memory(
734        cx: &mut LiftContext<'_>,
735        list: &WasmList<Self>,
736        dst: &mut impl Extend<Self>,
737    ) -> Result<()>
738    where
739        Self: Sized,
740    {
741        for i in 0..list.len {
742            dst.extend(Some(list.get_from_store(cx, i).unwrap()?));
743        }
744        Ok(())
745    }
746}
747
748// Macro to help generate "forwarding implementations" of `ComponentType` to
749// another type, used for wrappers in Rust like `&T`, `Box<T>`, etc. Note that
750// these wrappers only implement lowering because lifting native Rust types
751// cannot be done.
752macro_rules! forward_type_impls {
753    ($(
754        $(#[$attr:meta])*
755        ($($generics:tt)*) $a:ty => $b:ty,
756    )*) => ($(
757        $(#[$attr])*
758        unsafe impl <$($generics)*> ComponentType for $a {
759            type Lower = <$b as ComponentType>::Lower;
760
761            const ABI: CanonicalAbiInfo = <$b as ComponentType>::ABI;
762            const MAY_REQUIRE_REALLOC: bool = <$b as ComponentType>::MAY_REQUIRE_REALLOC;
763
764            #[inline]
765            fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
766                <$b as ComponentType>::typecheck(ty, types)
767            }
768        }
769    )*)
770}
771
772forward_type_impls! {
773    (T: ComponentType + ?Sized) &'_ T => T,
774    (T: ComponentType + ?Sized) Box<T> => T,
775    (T: ComponentType + ?Sized) alloc::sync::Arc<T> => T,
776    () String => str,
777    (T: ComponentType) Vec<T> => [T],
778    #[cfg(feature = "component-model-bytes")]
779    () bytes::Bytes => [u8],
780    #[cfg(feature = "component-model-bytes")]
781    () bytes::BytesMut => [u8],
782}
783
784macro_rules! forward_lowers {
785    ($(
786        $(#[$attr:meta])*
787        ($($generics:tt)*) $a:ty => $b:ty,
788    )*) => ($(
789        $(#[$attr])*
790        unsafe impl <$($generics)*> Lower for $a {
791            fn linear_lower_to_flat<U>(
792                &self,
793                cx: &mut LowerContext<'_, U>,
794                ty: InterfaceType,
795                dst: &mut MaybeUninit<Self::Lower>,
796            ) -> Result<()> {
797                <$b as Lower>::linear_lower_to_flat(self, cx, ty, dst)
798            }
799
800            fn linear_lower_to_memory<U>(
801                &self,
802                cx: &mut LowerContext<'_, U>,
803                ty: InterfaceType,
804                offset: usize,
805            ) -> Result<()> {
806                <$b as Lower>::linear_lower_to_memory(self, cx, ty, offset)
807            }
808        }
809    )*)
810}
811
812forward_lowers! {
813    (T: Lower + ?Sized) &'_ T => T,
814    (T: Lower + ?Sized) Box<T> => T,
815    (T: Lower + ?Sized) alloc::sync::Arc<T> => T,
816    () String => str,
817    (T: Lower) Vec<T> => [T],
818    #[cfg(feature = "component-model-bytes")]
819    () bytes::Bytes => [u8],
820    #[cfg(feature = "component-model-bytes")]
821    () bytes::BytesMut => [u8],
822}
823
824macro_rules! forward_string_lifts {
825    ($($a:ty,)*) => ($(
826        unsafe impl Lift for $a {
827            #[inline]
828            fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
829                let s = <WasmStr as Lift>::linear_lift_from_flat(cx, ty, src)?;
830                let encoding = cx.options().string_encoding;
831                Ok(s.to_str_from_memory(encoding, cx.memory())?.into())
832            }
833
834            #[inline]
835            fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
836                let s = <WasmStr as Lift>::linear_lift_from_memory(cx, ty, bytes)?;
837                let encoding = cx.options().string_encoding;
838                Ok(s.to_str_from_memory(encoding, cx.memory())?.into())
839            }
840        }
841    )*)
842}
843
844forward_string_lifts! {
845    Box<str>,
846    alloc::sync::Arc<str>,
847    String,
848}
849
850macro_rules! forward_list_lifts {
851    ($(
852        $(#[$attr:meta])*
853        ($($generics:tt)*) $a:ty => WasmList<$b:ty> $(( $via:ident $c:ty ))?,
854    )*) => ($(
855        $(#[$attr])*
856        unsafe impl <$($generics)*> Lift for $a {
857            fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
858                let list = <WasmList::<$b> as Lift>::linear_lift_from_flat(cx, ty, src)?;
859                let vec = <$b>::linear_lift_list_from_memory(cx, &list)?;
860                $(let vec = <$c>::from(vec);)?
861                Ok(Self::from(vec))
862            }
863
864            fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
865                let list = <WasmList::<$b> as Lift>::linear_lift_from_memory(cx, ty, bytes)?;
866                let vec = <$b>::linear_lift_list_from_memory(cx, &list)?;
867                $(let vec = <$c>::from(vec);)?
868                Ok(Self::from(vec))
869            }
870        }
871    )*)
872}
873
874forward_list_lifts! {
875    (T: Lift) Box<[T]> => WasmList<T>,
876    (T: Lift) alloc::sync::Arc<[T]> => WasmList<T>,
877    (T: Lift) Vec<T> => WasmList<T>,
878    #[cfg(feature = "component-model-bytes")]
879    () bytes::Bytes => WasmList<u8>,
880    // Note that `From<Vec<u8>> for BytesMut` is missing from the `bytes` crate
881    // and this is the subject of tokio-rs/bytes#615
882    #[cfg(feature = "component-model-bytes")]
883    () bytes::BytesMut => WasmList<u8> (via bytes::Bytes),
884}
885
886// Macro to help generate `ComponentType` implementations for primitive types
887// such as integers, char, bool, etc.
888macro_rules! integers {
889    ($($primitive:ident = $ty:ident in $field:ident/$get:ident with abi:$abi:ident,)*) => ($(
890        unsafe impl ComponentType for $primitive {
891            type Lower = ValRaw;
892
893            const ABI: CanonicalAbiInfo = CanonicalAbiInfo::$abi;
894
895            const MAY_REQUIRE_REALLOC: bool = false;
896
897            fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
898                match ty {
899                    InterfaceType::$ty => Ok(()),
900                    other => bail!("expected `{}` found `{}`", desc(&InterfaceType::$ty), desc(other))
901                }
902            }
903        }
904
905        unsafe impl Lower for $primitive {
906            #[inline]
907            #[allow(trivial_numeric_casts, reason = "macro-generated code")]
908            fn linear_lower_to_flat<T>(
909                &self,
910                _cx: &mut LowerContext<'_, T>,
911                ty: InterfaceType,
912                dst: &mut MaybeUninit<Self::Lower>,
913            ) -> Result<()> {
914                debug_assert!(matches!(ty, InterfaceType::$ty));
915                dst.write(ValRaw::$field(*self as $field));
916                Ok(())
917            }
918
919            #[inline]
920            fn linear_lower_to_memory<T>(
921                &self,
922                cx: &mut LowerContext<'_, T>,
923                ty: InterfaceType,
924                offset: usize,
925            ) -> Result<()> {
926                debug_assert!(matches!(ty, InterfaceType::$ty));
927                debug_assert!(offset % Self::SIZE32 == 0);
928                *cx.get(offset) = self.to_le_bytes();
929                Ok(())
930            }
931
932            fn linear_store_list_to_memory<T>(
933                cx: &mut LowerContext<'_, T>,
934                ty: InterfaceType,
935                offset: usize,
936                items: &[Self],
937            ) -> Result<()> {
938                debug_assert!(matches!(ty, InterfaceType::$ty));
939
940                // Double-check that the CM alignment is at least the host's
941                // alignment for this type which should be true for all
942                // platforms.
943                assert!((Self::ALIGN32 as usize) >= mem::align_of::<Self>());
944
945                // Slice `cx`'s memory to the window that we'll be modifying.
946                // This should all have already been verified in terms of
947                // alignment and sizing meaning that these assertions here are
948                // not truly necessary but are instead double-checks.
949                //
950                // Note that we're casting a `[u8]` slice to `[Self]` with
951                // `align_to_mut` which is not safe in general but is safe in
952                // our specific case as all `u8` patterns are valid `Self`
953                // patterns since `Self` is an integral type.
954                let dst = &mut cx.as_slice_mut()[offset..][..items.len() * Self::SIZE32];
955                let (before, middle, end) = unsafe { dst.align_to_mut::<Self>() };
956                assert!(before.is_empty() && end.is_empty());
957                assert_eq!(middle.len(), items.len());
958
959                // And with all that out of the way perform the copying loop.
960                // This is not a `copy_from_slice` because endianness needs to
961                // be handled here, but LLVM should pretty easily transform this
962                // into a memcpy on little-endian platforms.
963                for (dst, src) in middle.iter_mut().zip(items) {
964                    *dst = src.to_le();
965                }
966                Ok(())
967            }
968        }
969
970        unsafe impl Lift for $primitive {
971            #[inline]
972            #[allow(
973                trivial_numeric_casts,
974                clippy::cast_possible_truncation,
975                reason = "macro-generated code"
976            )]
977            fn linear_lift_from_flat(_cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
978                debug_assert!(matches!(ty, InterfaceType::$ty));
979                Ok(src.$get() as $primitive)
980            }
981
982            #[inline]
983            fn linear_lift_from_memory(_cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
984                debug_assert!(matches!(ty, InterfaceType::$ty));
985                debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0);
986                Ok($primitive::from_le_bytes(*bytes.as_array().unwrap()))
987            }
988
989            fn linear_lift_into_from_memory(
990                cx: &mut LiftContext<'_>,
991                list: &WasmList<Self>,
992                dst: &mut impl Extend<Self>,
993            ) -> Result<()>
994            where
995                Self: Sized,
996            {
997                dst.extend(list._as_le_slice(cx.memory())
998                           .iter()
999                           .map(|i| Self::from_le(*i)));
1000                Ok(())
1001            }
1002        }
1003    )*)
1004}
1005
1006integers! {
1007    i8 = S8 in i32/get_i32 with abi:SCALAR1,
1008    u8 = U8 in u32/get_u32 with abi:SCALAR1,
1009    i16 = S16 in i32/get_i32 with abi:SCALAR2,
1010    u16 = U16 in u32/get_u32 with abi:SCALAR2,
1011    i32 = S32 in i32/get_i32 with abi:SCALAR4,
1012    u32 = U32 in u32/get_u32 with abi:SCALAR4,
1013    i64 = S64 in i64/get_i64 with abi:SCALAR8,
1014    u64 = U64 in u64/get_u64 with abi:SCALAR8,
1015}
1016
1017macro_rules! floats {
1018    ($($float:ident/$get_float:ident = $ty:ident with abi:$abi:ident)*) => ($(const _: () = {
1019        unsafe impl ComponentType for $float {
1020            type Lower = ValRaw;
1021
1022            const ABI: CanonicalAbiInfo = CanonicalAbiInfo::$abi;
1023            const MAY_REQUIRE_REALLOC: bool = false;
1024
1025            fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1026                match ty {
1027                    InterfaceType::$ty => Ok(()),
1028                    other => bail!("expected `{}` found `{}`", desc(&InterfaceType::$ty), desc(other))
1029                }
1030            }
1031        }
1032
1033        unsafe impl Lower for $float {
1034            #[inline]
1035            fn linear_lower_to_flat<T>(
1036                &self,
1037                _cx: &mut LowerContext<'_, T>,
1038                ty: InterfaceType,
1039                dst: &mut MaybeUninit<Self::Lower>,
1040            ) -> Result<()> {
1041                debug_assert!(matches!(ty, InterfaceType::$ty));
1042                dst.write(ValRaw::$float(self.to_bits()));
1043                Ok(())
1044            }
1045
1046            #[inline]
1047            fn linear_lower_to_memory<T>(
1048                &self,
1049                cx: &mut LowerContext<'_, T>,
1050                ty: InterfaceType,
1051                offset: usize,
1052            ) -> Result<()> {
1053                debug_assert!(matches!(ty, InterfaceType::$ty));
1054                debug_assert!(offset % Self::SIZE32 == 0);
1055                let ptr = cx.get(offset);
1056                *ptr = self.to_bits().to_le_bytes();
1057                Ok(())
1058            }
1059
1060            fn linear_store_list_to_memory<T>(
1061                cx: &mut LowerContext<'_, T>,
1062                ty: InterfaceType,
1063                offset: usize,
1064                items: &[Self],
1065            ) -> Result<()> {
1066                debug_assert!(matches!(ty, InterfaceType::$ty));
1067
1068                // Double-check that the CM alignment is at least the host's
1069                // alignment for this type which should be true for all
1070                // platforms.
1071                assert!((Self::ALIGN32 as usize) >= mem::align_of::<Self>());
1072
1073                // Slice `cx`'s memory to the window that we'll be modifying.
1074                // This should all have already been verified in terms of
1075                // alignment and sizing meaning that these assertions here are
1076                // not truly necessary but are instead double-checks.
1077                let dst = &mut cx.as_slice_mut()[offset..][..items.len() * Self::SIZE32];
1078                assert!(dst.as_ptr().cast::<Self>().is_aligned());
1079
1080                // And with all that out of the way perform the copying loop.
1081                // This is not a `copy_from_slice` because endianness needs to
1082                // be handled here, but LLVM should pretty easily transform this
1083                // into a memcpy on little-endian platforms.
1084                // TODO use `as_chunks` when https://github.com/rust-lang/rust/issues/74985
1085                // is stabilized
1086                let (dst, rest) = dst.as_chunks_mut::<{Self::SIZE32}>();
1087                debug_assert!(rest.is_empty());
1088                for (dst, src) in iter::zip(dst, items) {
1089                    *dst = src.to_le_bytes();
1090                }
1091                Ok(())
1092            }
1093        }
1094
1095        unsafe impl Lift for $float {
1096            #[inline]
1097            fn linear_lift_from_flat(_cx: &mut LiftContext<'_>, ty: InterfaceType, src: &Self::Lower) -> Result<Self> {
1098                debug_assert!(matches!(ty, InterfaceType::$ty));
1099                Ok($float::from_bits(src.$get_float()))
1100            }
1101
1102            #[inline]
1103            fn linear_lift_from_memory(_cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
1104                debug_assert!(matches!(ty, InterfaceType::$ty));
1105                debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0);
1106                Ok($float::from_le_bytes(*bytes.as_array().unwrap()))
1107            }
1108
1109            fn linear_lift_list_from_memory(cx: &mut LiftContext<'_>, list: &WasmList<Self>) -> Result<Vec<Self>> where Self: Sized {
1110                // See comments in `WasmList::get` for the panicking indexing
1111                let byte_size = list.len * mem::size_of::<Self>();
1112                let bytes = &cx.memory()[list.ptr..][..byte_size];
1113
1114                // The canonical ABI requires that everything is aligned to its
1115                // own size, so this should be an aligned array.
1116                assert!(bytes.as_ptr().cast::<Self>().is_aligned());
1117
1118                // Copy the resulting slice to a new Vec, handling endianness
1119                // in the process
1120                // TODO use `as_chunks` when https://github.com/rust-lang/rust/issues/74985
1121                // is stabilized
1122                Ok(
1123                    bytes
1124                        .chunks_exact(Self::SIZE32)
1125                        .map(|i| $float::from_le_bytes(*i.as_array().unwrap()))
1126                        .collect()
1127                )
1128            }
1129        }
1130    };)*)
1131}
1132
1133floats! {
1134    f32/get_f32 = Float32 with abi:SCALAR4
1135    f64/get_f64 = Float64 with abi:SCALAR8
1136}
1137
1138unsafe impl ComponentType for bool {
1139    type Lower = ValRaw;
1140
1141    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR1;
1142    const MAY_REQUIRE_REALLOC: bool = false;
1143
1144    fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1145        match ty {
1146            InterfaceType::Bool => Ok(()),
1147            other => bail!("expected `bool` found `{}`", desc(other)),
1148        }
1149    }
1150}
1151
1152unsafe impl Lower for bool {
1153    fn linear_lower_to_flat<T>(
1154        &self,
1155        _cx: &mut LowerContext<'_, T>,
1156        ty: InterfaceType,
1157        dst: &mut MaybeUninit<Self::Lower>,
1158    ) -> Result<()> {
1159        debug_assert!(matches!(ty, InterfaceType::Bool));
1160        dst.write(ValRaw::i32(*self as i32));
1161        Ok(())
1162    }
1163
1164    fn linear_lower_to_memory<T>(
1165        &self,
1166        cx: &mut LowerContext<'_, T>,
1167        ty: InterfaceType,
1168        offset: usize,
1169    ) -> Result<()> {
1170        debug_assert!(matches!(ty, InterfaceType::Bool));
1171        debug_assert!(offset % Self::SIZE32 == 0);
1172        cx.get::<1>(offset)[0] = *self as u8;
1173        Ok(())
1174    }
1175}
1176
1177unsafe impl Lift for bool {
1178    #[inline]
1179    fn linear_lift_from_flat(
1180        _cx: &mut LiftContext<'_>,
1181        ty: InterfaceType,
1182        src: &Self::Lower,
1183    ) -> Result<Self> {
1184        debug_assert!(matches!(ty, InterfaceType::Bool));
1185        match src.get_i32() {
1186            0 => Ok(false),
1187            _ => Ok(true),
1188        }
1189    }
1190
1191    #[inline]
1192    fn linear_lift_from_memory(
1193        _cx: &mut LiftContext<'_>,
1194        ty: InterfaceType,
1195        bytes: &[u8],
1196    ) -> Result<Self> {
1197        debug_assert!(matches!(ty, InterfaceType::Bool));
1198        match bytes[0] {
1199            0 => Ok(false),
1200            _ => Ok(true),
1201        }
1202    }
1203}
1204
1205unsafe impl ComponentType for char {
1206    type Lower = ValRaw;
1207
1208    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::SCALAR4;
1209    const MAY_REQUIRE_REALLOC: bool = false;
1210
1211    fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1212        match ty {
1213            InterfaceType::Char => Ok(()),
1214            other => bail!("expected `char` found `{}`", desc(other)),
1215        }
1216    }
1217}
1218
1219unsafe impl Lower for char {
1220    #[inline]
1221    fn linear_lower_to_flat<T>(
1222        &self,
1223        _cx: &mut LowerContext<'_, T>,
1224        ty: InterfaceType,
1225        dst: &mut MaybeUninit<Self::Lower>,
1226    ) -> Result<()> {
1227        debug_assert!(matches!(ty, InterfaceType::Char));
1228        dst.write(ValRaw::u32(u32::from(*self)));
1229        Ok(())
1230    }
1231
1232    #[inline]
1233    fn linear_lower_to_memory<T>(
1234        &self,
1235        cx: &mut LowerContext<'_, T>,
1236        ty: InterfaceType,
1237        offset: usize,
1238    ) -> Result<()> {
1239        debug_assert!(matches!(ty, InterfaceType::Char));
1240        debug_assert!(offset % Self::SIZE32 == 0);
1241        *cx.get::<4>(offset) = u32::from(*self).to_le_bytes();
1242        Ok(())
1243    }
1244}
1245
1246unsafe impl Lift for char {
1247    #[inline]
1248    fn linear_lift_from_flat(
1249        _cx: &mut LiftContext<'_>,
1250        ty: InterfaceType,
1251        src: &Self::Lower,
1252    ) -> Result<Self> {
1253        debug_assert!(matches!(ty, InterfaceType::Char));
1254        Ok(char::try_from(src.get_u32())?)
1255    }
1256
1257    #[inline]
1258    fn linear_lift_from_memory(
1259        _cx: &mut LiftContext<'_>,
1260        ty: InterfaceType,
1261        bytes: &[u8],
1262    ) -> Result<Self> {
1263        debug_assert!(matches!(ty, InterfaceType::Char));
1264        debug_assert!((bytes.as_ptr() as usize) % Self::SIZE32 == 0);
1265        let bits = u32::from_le_bytes(*bytes.as_array().unwrap());
1266        Ok(char::try_from(bits)?)
1267    }
1268}
1269
1270fn lift_pointer_pair_from_flat(
1271    cx: &mut LiftContext<'_>,
1272    src: &[ValRaw; 2],
1273) -> Result<(usize, usize)> {
1274    // FIXME(#4311): needs memory64 treatment
1275    let _ = cx; // this will be needed for memory64 in the future
1276    let ptr = src[0].get_u32();
1277    let len = src[1].get_u32();
1278    Ok((usize::try_from(ptr)?, usize::try_from(len)?))
1279}
1280
1281fn lift_pointer_pair_from_memory(cx: &mut LiftContext<'_>, bytes: &[u8]) -> Result<(usize, usize)> {
1282    // FIXME(#4311): needs memory64 treatment
1283    let _ = cx; // this will be needed for memory64 in the future
1284    let ptr = u32::from_le_bytes(*bytes[..4].as_array().unwrap());
1285    let len = u32::from_le_bytes(*bytes[4..].as_array().unwrap());
1286    Ok((usize::try_from(ptr)?, usize::try_from(len)?))
1287}
1288
1289fn lower_pointer_pair_to_flat<T>(
1290    cx: &mut LowerContext<T>,
1291    dst: &mut MaybeUninit<[ValRaw; 2]>,
1292    ptr: usize,
1293    len: usize,
1294) {
1295    // See "WRITEPTR64" above for why this is always storing a 64-bit
1296    // integer.
1297    let _ = cx; // this will eventually be needed for memory64 information.
1298    map_maybe_uninit!(dst[0]).write(ValRaw::i64(ptr as i64));
1299    map_maybe_uninit!(dst[1]).write(ValRaw::i64(len as i64));
1300}
1301
1302fn lower_pointer_pair_to_memory<T>(
1303    cx: &mut LowerContext<T>,
1304    offset: usize,
1305    ptr: usize,
1306    len: usize,
1307) {
1308    // FIXME(#4311): needs memory64 handling
1309    *cx.get(offset + 0) = u32::try_from(ptr).unwrap().to_le_bytes();
1310    *cx.get(offset + 4) = u32::try_from(len).unwrap().to_le_bytes();
1311}
1312
1313// FIXME(#4311): these probably need different constants for memory64
1314const UTF16_TAG: usize = 1 << 31;
1315const MAX_STRING_BYTE_LENGTH: usize = (1 << 31) - 1;
1316
1317// Note that this is similar to `ComponentType for WasmStr` except it can only
1318// be used for lowering, not lifting.
1319unsafe impl ComponentType for str {
1320    type Lower = [ValRaw; 2];
1321
1322    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1323
1324    fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1325        match ty {
1326            InterfaceType::String => Ok(()),
1327            other => bail!("expected `string` found `{}`", desc(other)),
1328        }
1329    }
1330}
1331
1332unsafe impl Lower for str {
1333    fn linear_lower_to_flat<T>(
1334        &self,
1335        cx: &mut LowerContext<'_, T>,
1336        ty: InterfaceType,
1337        dst: &mut MaybeUninit<[ValRaw; 2]>,
1338    ) -> Result<()> {
1339        debug_assert!(matches!(ty, InterfaceType::String));
1340        let (ptr, len) = lower_string(cx, self)?;
1341        lower_pointer_pair_to_flat(cx, dst, ptr, len);
1342        Ok(())
1343    }
1344
1345    fn linear_lower_to_memory<T>(
1346        &self,
1347        cx: &mut LowerContext<'_, T>,
1348        ty: InterfaceType,
1349        offset: usize,
1350    ) -> Result<()> {
1351        debug_assert!(matches!(ty, InterfaceType::String));
1352        debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
1353        let (ptr, len) = lower_string(cx, self)?;
1354        lower_pointer_pair_to_memory(cx, offset, ptr, len);
1355        Ok(())
1356    }
1357}
1358
1359fn lower_string<T>(cx: &mut LowerContext<'_, T>, string: &str) -> Result<(usize, usize)> {
1360    // Note that in general the wasm module can't assume anything about what the
1361    // host strings are encoded as. Additionally hosts are allowed to have
1362    // differently-encoded strings at runtime. Finally when copying a string
1363    // into wasm it's somewhat strict in the sense that the various patterns of
1364    // allocation and such are already dictated for us.
1365    //
1366    // In general what this means is that when copying a string from the host
1367    // into the destination we need to follow one of the cases of copying into
1368    // WebAssembly. It doesn't particularly matter which case as long as it ends
1369    // up in the right encoding. For example a destination encoding of
1370    // latin1+utf16 has a number of ways to get copied into and we do something
1371    // here that isn't the default "utf8 to latin1+utf16" since we have access
1372    // to simd-accelerated helpers in the `encoding_rs` crate. This is ok though
1373    // because we can fake that the host string was already stored in latin1
1374    // format and follow that copy pattern instead.
1375    match cx.options().string_encoding {
1376        // This corresponds to `store_string_copy` in the canonical ABI where
1377        // the host's representation is utf-8 and the wasm module wants utf-8 so
1378        // a copy is all that's needed (and the `realloc` can be precise for the
1379        // initial memory allocation).
1380        StringEncoding::Utf8 => {
1381            if string.len() > MAX_STRING_BYTE_LENGTH {
1382                bail!(
1383                    "string length of {} too large to copy into wasm",
1384                    string.len()
1385                );
1386            }
1387            let ptr = cx.realloc(0, 0, 1, string.len())?;
1388            cx.as_slice_mut()[ptr..][..string.len()].copy_from_slice(string.as_bytes());
1389            Ok((ptr, string.len()))
1390        }
1391
1392        // This corresponds to `store_utf8_to_utf16` in the canonical ABI. Here
1393        // an over-large allocation is performed and then shrunk afterwards if
1394        // necessary.
1395        StringEncoding::Utf16 => {
1396            let size = string.len() * 2;
1397            if size > MAX_STRING_BYTE_LENGTH {
1398                bail!(
1399                    "string length of {} too large to copy into wasm",
1400                    string.len()
1401                );
1402            }
1403            let mut ptr = cx.realloc(0, 0, 2, size)?;
1404            let mut copied = 0;
1405            let bytes = &mut cx.as_slice_mut()[ptr..][..size];
1406            for (u, bytes) in string.encode_utf16().zip(bytes.chunks_mut(2)) {
1407                let u_bytes = u.to_le_bytes();
1408                bytes[0] = u_bytes[0];
1409                bytes[1] = u_bytes[1];
1410                copied += 1;
1411            }
1412            if (copied * 2) < size {
1413                ptr = cx.realloc(ptr, size, 2, copied * 2)?;
1414            }
1415            Ok((ptr, copied))
1416        }
1417
1418        StringEncoding::CompactUtf16 => {
1419            // This corresponds to `store_string_to_latin1_or_utf16`
1420            let bytes = string.as_bytes();
1421            let mut iter = string.char_indices();
1422            let mut ptr = cx.realloc(0, 0, 2, bytes.len())?;
1423            let mut dst = &mut cx.as_slice_mut()[ptr..][..bytes.len()];
1424            let mut result = 0;
1425            while let Some((i, ch)) = iter.next() {
1426                // Test if this `char` fits into the latin1 encoding.
1427                if let Ok(byte) = u8::try_from(u32::from(ch)) {
1428                    dst[result] = byte;
1429                    result += 1;
1430                    continue;
1431                }
1432
1433                // .. if utf16 is forced to be used then the allocation is
1434                // bumped up to the maximum size.
1435                let worst_case = bytes
1436                    .len()
1437                    .checked_mul(2)
1438                    .ok_or_else(|| format_err!("byte length overflow"))?;
1439                if worst_case > MAX_STRING_BYTE_LENGTH {
1440                    bail!("byte length too large");
1441                }
1442                ptr = cx.realloc(ptr, bytes.len(), 2, worst_case)?;
1443                dst = &mut cx.as_slice_mut()[ptr..][..worst_case];
1444
1445                // Previously encoded latin1 bytes are inflated to their 16-bit
1446                // size for utf16
1447                for i in (0..result).rev() {
1448                    dst[2 * i] = dst[i];
1449                    dst[2 * i + 1] = 0;
1450                }
1451
1452                // and then the remainder of the string is encoded.
1453                for (u, bytes) in string[i..]
1454                    .encode_utf16()
1455                    .zip(dst[2 * result..].chunks_mut(2))
1456                {
1457                    let u_bytes = u.to_le_bytes();
1458                    bytes[0] = u_bytes[0];
1459                    bytes[1] = u_bytes[1];
1460                    result += 1;
1461                }
1462                if worst_case > 2 * result {
1463                    ptr = cx.realloc(ptr, worst_case, 2, 2 * result)?;
1464                }
1465                return Ok((ptr, result | UTF16_TAG));
1466            }
1467            if result < bytes.len() {
1468                ptr = cx.realloc(ptr, bytes.len(), 2, result)?;
1469            }
1470            Ok((ptr, result))
1471        }
1472    }
1473}
1474
1475/// Representation of a string located in linear memory in a WebAssembly
1476/// instance.
1477///
1478/// This type can be used in place of `String` and `str` for string-taking APIs
1479/// in some situations. The purpose of this type is to represent a range of
1480/// validated bytes within a component but does not actually copy the bytes. The
1481/// primary method, [`WasmStr::to_str`], attempts to return a reference to the
1482/// string directly located in the component's memory, avoiding a copy into the
1483/// host if possible.
1484///
1485/// The downside of this type, however, is that accessing a string requires a
1486/// [`Store`](crate::Store) pointer (via [`StoreContext`]). Bindings generated
1487/// by [`bindgen!`](crate::component::bindgen), for example, do not have access
1488/// to [`StoreContext`] and thus can't use this type.
1489///
1490/// This is intended for more advanced use cases such as defining functions
1491/// directly in a [`Linker`](crate::component::Linker). It's expected that in
1492/// the future [`bindgen!`](crate::component::bindgen) will also have a way to
1493/// use this type.
1494///
1495/// This type is used with [`TypedFunc`], for example, when WebAssembly returns
1496/// a string. This type cannot be used to give a string to WebAssembly, instead
1497/// `&str` should be used for that (since it's coming from the host).
1498///
1499/// Note that this type represents an in-bounds string in linear memory, but it
1500/// does not represent a valid string (e.g. valid utf-8). Validation happens
1501/// when [`WasmStr::to_str`] is called.
1502///
1503/// Also note that this type does not implement [`Lower`], it only implements
1504/// [`Lift`].
1505pub struct WasmStr {
1506    ptr: usize,
1507    len: usize,
1508    options: OptionsIndex,
1509    instance: Instance,
1510}
1511
1512impl WasmStr {
1513    pub(crate) fn new(ptr: usize, len: usize, cx: &mut LiftContext<'_>) -> Result<WasmStr> {
1514        let (byte_len, align) = match cx.options().string_encoding {
1515            StringEncoding::Utf8 => (Some(len), 1_usize),
1516            StringEncoding::Utf16 => (len.checked_mul(2), 2),
1517            StringEncoding::CompactUtf16 => {
1518                if len & UTF16_TAG == 0 {
1519                    (Some(len), 2)
1520                } else {
1521                    ((len ^ UTF16_TAG).checked_mul(2), 2)
1522                }
1523            }
1524        };
1525        debug_assert!(align.is_power_of_two());
1526        if ptr & (align - 1) != 0 {
1527            bail!("string pointer not aligned to {align}");
1528        }
1529        match byte_len.and_then(|len| ptr.checked_add(len)) {
1530            Some(n) if n <= cx.memory().len() => cx.consume_fuel(n - ptr)?,
1531            _ => bail!("string pointer/length out of bounds of memory"),
1532        }
1533        Ok(WasmStr {
1534            ptr,
1535            len,
1536            options: cx.options_index(),
1537            instance: cx.instance_handle(),
1538        })
1539    }
1540
1541    /// Returns the underlying string that this cursor points to.
1542    ///
1543    /// Note that this will internally decode the string from the wasm's
1544    /// encoding to utf-8 and additionally perform validation.
1545    ///
1546    /// The `store` provided must be the store where this string lives to
1547    /// access the correct memory.
1548    ///
1549    /// # Errors
1550    ///
1551    /// Returns an error if the string wasn't encoded correctly (e.g. invalid
1552    /// utf-8).
1553    ///
1554    /// # Panics
1555    ///
1556    /// Panics if this string is not owned by `store`.
1557    //
1558    // TODO: should add accessors for specifically utf-8 and utf-16 that perhaps
1559    // in an opt-in basis don't do validation. Additionally there should be some
1560    // method that returns `[u16]` after validating to avoid the utf16-to-utf8
1561    // transcode.
1562    pub fn to_str<'a, T: 'static>(
1563        &self,
1564        store: impl Into<StoreContext<'a, T>>,
1565    ) -> Result<Cow<'a, str>> {
1566        let store = store.into().0;
1567        let memory = self.instance.options_memory(store, self.options);
1568        let encoding = self.instance.options(store, self.options).string_encoding;
1569        self.to_str_from_memory(encoding, memory)
1570    }
1571
1572    pub(crate) fn to_str_from_memory<'a>(
1573        &self,
1574        encoding: StringEncoding,
1575        memory: &'a [u8],
1576    ) -> Result<Cow<'a, str>> {
1577        match encoding {
1578            StringEncoding::Utf8 => self.decode_utf8(memory),
1579            StringEncoding::Utf16 => self.decode_utf16(memory, self.len),
1580            StringEncoding::CompactUtf16 => {
1581                if self.len & UTF16_TAG == 0 {
1582                    self.decode_latin1(memory)
1583                } else {
1584                    self.decode_utf16(memory, self.len ^ UTF16_TAG)
1585                }
1586            }
1587        }
1588    }
1589
1590    fn decode_utf8<'a>(&self, memory: &'a [u8]) -> Result<Cow<'a, str>> {
1591        // Note that bounds-checking already happen in construction of `WasmStr`
1592        // so this is never expected to panic. This could theoretically be
1593        // unchecked indexing if we're feeling wild enough.
1594        Ok(str::from_utf8(&memory[self.ptr..][..self.len])?.into())
1595    }
1596
1597    fn decode_utf16<'a>(&self, memory: &'a [u8], len: usize) -> Result<Cow<'a, str>> {
1598        // See notes in `decode_utf8` for why this is panicking indexing.
1599        let (chunks, rest) = &memory[self.ptr..][..len * 2].as_chunks::<2>();
1600        debug_assert!(rest.is_empty());
1601        Ok(
1602            core::char::decode_utf16(chunks.iter().map(|chunk| u16::from_le_bytes(*chunk)))
1603                .collect::<Result<String, _>>()?
1604                .into(),
1605        )
1606    }
1607
1608    fn decode_latin1<'a>(&self, memory: &'a [u8]) -> Result<Cow<'a, str>> {
1609        // See notes in `decode_utf8` for why this is panicking indexing.
1610        Ok(encoding_rs::mem::decode_latin1(
1611            &memory[self.ptr..][..self.len],
1612        ))
1613    }
1614}
1615
1616// Note that this is similar to `ComponentType for str` except it can only be
1617// used for lifting, not lowering.
1618unsafe impl ComponentType for WasmStr {
1619    type Lower = <str as ComponentType>::Lower;
1620
1621    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1622
1623    fn typecheck(ty: &InterfaceType, _types: &InstanceType<'_>) -> Result<()> {
1624        match ty {
1625            InterfaceType::String => Ok(()),
1626            other => bail!("expected `string` found `{}`", desc(other)),
1627        }
1628    }
1629}
1630
1631unsafe impl Lift for WasmStr {
1632    #[inline]
1633    fn linear_lift_from_flat(
1634        cx: &mut LiftContext<'_>,
1635        ty: InterfaceType,
1636        src: &Self::Lower,
1637    ) -> Result<Self> {
1638        debug_assert!(matches!(ty, InterfaceType::String));
1639        let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
1640        WasmStr::new(ptr, len, cx)
1641    }
1642
1643    #[inline]
1644    fn linear_lift_from_memory(
1645        cx: &mut LiftContext<'_>,
1646        ty: InterfaceType,
1647        bytes: &[u8],
1648    ) -> Result<Self> {
1649        debug_assert!(matches!(ty, InterfaceType::String));
1650        debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
1651        let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
1652        WasmStr::new(ptr, len, cx)
1653    }
1654}
1655
1656unsafe impl<T> ComponentType for [T]
1657where
1658    T: ComponentType,
1659{
1660    type Lower = [ValRaw; 2];
1661
1662    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1663
1664    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1665        match ty {
1666            InterfaceType::List(t) => T::typecheck(&types.types[*t].element, types),
1667            other => bail!("expected `list` found `{}`", desc(other)),
1668        }
1669    }
1670}
1671
1672unsafe impl<T> Lower for [T]
1673where
1674    T: Lower,
1675{
1676    fn linear_lower_to_flat<U>(
1677        &self,
1678        cx: &mut LowerContext<'_, U>,
1679        ty: InterfaceType,
1680        dst: &mut MaybeUninit<[ValRaw; 2]>,
1681    ) -> Result<()> {
1682        let elem = match ty {
1683            InterfaceType::List(i) => cx.types[i].element,
1684            _ => bad_type_info(),
1685        };
1686        let (ptr, len) = lower_list(cx, elem, self)?;
1687        lower_pointer_pair_to_flat(cx, dst, ptr, len);
1688        Ok(())
1689    }
1690
1691    fn linear_lower_to_memory<U>(
1692        &self,
1693        cx: &mut LowerContext<'_, U>,
1694        ty: InterfaceType,
1695        offset: usize,
1696    ) -> Result<()> {
1697        let elem = match ty {
1698            InterfaceType::List(i) => cx.types[i].element,
1699            _ => bad_type_info(),
1700        };
1701        debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
1702        let (ptr, len) = lower_list(cx, elem, self)?;
1703        lower_pointer_pair_to_memory(cx, offset, ptr, len);
1704        Ok(())
1705    }
1706}
1707
1708// FIXME: this is not a memcpy for `T` where `T` is something like `u8`.
1709//
1710// Some attempts to fix this have proved not fruitful. In isolation an attempt
1711// was made where:
1712//
1713// * `MemoryMut` stored a `*mut [u8]` as its "last view" of memory to avoid
1714//   reloading the base pointer constantly. This view is reset on `realloc`.
1715// * The bounds-checks in `MemoryMut::get` were removed (replaced with unsafe
1716//   indexing)
1717//
1718// Even then though this didn't correctly vectorized for `Vec<u8>`. It's not
1719// entirely clear why but it appeared that it's related to reloading the base
1720// pointer to memory (I guess from `MemoryMut` itself?). Overall I'm not really
1721// clear on what's happening there, but this is surely going to be a performance
1722// bottleneck in the future.
1723fn lower_list<T, U>(
1724    cx: &mut LowerContext<'_, U>,
1725    ty: InterfaceType,
1726    list: &[T],
1727) -> Result<(usize, usize)>
1728where
1729    T: Lower,
1730{
1731    let elem_size = T::SIZE32;
1732    let size = list
1733        .len()
1734        .checked_mul(elem_size)
1735        .ok_or_else(|| format_err!("size overflow copying a list"))?;
1736    let ptr = cx.realloc(0, 0, T::ALIGN32, size)?;
1737    T::linear_store_list_to_memory(cx, ty, ptr, list)?;
1738    Ok((ptr, list.len()))
1739}
1740
1741/// Representation of a list of values that are owned by a WebAssembly instance.
1742///
1743/// For some more commentary about the rationale for this type see the
1744/// documentation of [`WasmStr`]. In summary this type can avoid a copy when
1745/// passing data to the host in some situations but is additionally more
1746/// cumbersome to use by requiring a [`Store`](crate::Store) to be provided.
1747///
1748/// This type is used whenever a `(list T)` is returned from a [`TypedFunc`],
1749/// for example. This type represents a list of values that are stored in linear
1750/// memory which are waiting to be read.
1751///
1752/// Note that this type represents only a valid range of bytes for the list
1753/// itself, it does not represent validity of the elements themselves and that's
1754/// performed when they're iterated.
1755///
1756/// Note that this type does not implement the [`Lower`] trait, only [`Lift`].
1757pub struct WasmList<T> {
1758    ptr: usize,
1759    len: usize,
1760    options: OptionsIndex,
1761    elem: InterfaceType,
1762    instance: Instance,
1763    _marker: marker::PhantomData<T>,
1764}
1765
1766impl<T: Lift> WasmList<T> {
1767    pub(crate) fn new(
1768        ptr: usize,
1769        len: usize,
1770        cx: &mut LiftContext<'_>,
1771        elem: InterfaceType,
1772    ) -> Result<WasmList<T>> {
1773        match len
1774            .checked_mul(T::SIZE32)
1775            .and_then(|len| ptr.checked_add(len))
1776        {
1777            Some(n) if n <= cx.memory().len() => cx.consume_fuel_array(len, size_of::<T>())?,
1778            _ => bail!("list pointer/length out of bounds of memory"),
1779        }
1780        if ptr % usize::try_from(T::ALIGN32)? != 0 {
1781            bail!("list pointer is not aligned")
1782        }
1783        Ok(WasmList {
1784            ptr,
1785            len,
1786            options: cx.options_index(),
1787            elem,
1788            instance: cx.instance_handle(),
1789            _marker: marker::PhantomData,
1790        })
1791    }
1792
1793    /// Returns the item length of this vector
1794    #[inline]
1795    pub fn len(&self) -> usize {
1796        self.len
1797    }
1798
1799    /// Gets the `n`th element of this list.
1800    ///
1801    /// Returns `None` if `index` is out of bounds. Returns `Some(Err(..))` if
1802    /// the value couldn't be decoded (it was invalid). Returns `Some(Ok(..))`
1803    /// if the value is valid.
1804    ///
1805    /// # Panics
1806    ///
1807    /// This function will panic if the string did not originally come from the
1808    /// `store` specified.
1809    //
1810    // TODO: given that interface values are intended to be consumed in one go
1811    // should we even expose a random access iteration API? In theory all
1812    // consumers should be validating through the iterator.
1813    pub fn get(&self, mut store: impl AsContextMut, index: usize) -> Option<Result<T>> {
1814        let store = store.as_context_mut().0;
1815        let mut cx = match LiftContext::new(store, self.options, self.instance) {
1816            Ok(cx) => cx,
1817            Err(e) => return Some(Err(e)),
1818        };
1819        self.get_from_store(&mut cx, index)
1820    }
1821
1822    fn get_from_store(&self, cx: &mut LiftContext<'_>, index: usize) -> Option<Result<T>> {
1823        if index >= self.len {
1824            return None;
1825        }
1826        // Note that this is using panicking indexing and this is expected to
1827        // never fail. The bounds-checking here happened during the construction
1828        // of the `WasmList` itself which means these should always be in-bounds
1829        // (and wasm memory can only grow). This could theoretically be
1830        // unchecked indexing if we're confident enough and it's actually a perf
1831        // issue one day.
1832        let bytes = &cx.memory()[self.ptr + index * T::SIZE32..][..T::SIZE32];
1833        Some(T::linear_lift_from_memory(cx, self.elem, bytes))
1834    }
1835
1836    /// Returns an iterator over the elements of this list.
1837    ///
1838    /// Each item of the list may fail to decode and is represented through the
1839    /// `Result` value of the iterator.
1840    pub fn iter<'a, U: 'static>(
1841        &'a self,
1842        store: impl Into<StoreContextMut<'a, U>>,
1843    ) -> Result<impl ExactSizeIterator<Item = Result<T>> + 'a> {
1844        let store = store.into().0;
1845        let mut cx = LiftContext::new(store, self.options, self.instance)?;
1846        Ok((0..self.len).map(move |i| self.get_from_store(&mut cx, i).unwrap()))
1847    }
1848}
1849
1850macro_rules! raw_wasm_list_accessors {
1851    ($($i:ident)*) => ($(
1852        impl WasmList<$i> {
1853            /// Get access to the raw underlying memory for this list.
1854            ///
1855            /// This method will return a direct slice into the original wasm
1856            /// module's linear memory where the data for this slice is stored.
1857            /// This allows the embedder to have efficient access to the
1858            /// underlying memory if needed and avoid copies and such if
1859            /// desired.
1860            ///
1861            /// Note that multi-byte integers are stored in little-endian format
1862            /// so portable processing of this slice must be aware of the host's
1863            /// byte-endianness. The `from_le` constructors in the Rust standard
1864            /// library should be suitable for converting from little-endian.
1865            ///
1866            /// # Panics
1867            ///
1868            /// Panics if the `store` provided is not the one from which this
1869            /// slice originated.
1870            pub fn as_le_slice<'a, T: 'static>(&self, store: impl Into<StoreContext<'a, T>>) -> &'a [$i] {
1871                let memory = self.instance.options_memory(store.into().0, self.options);
1872                self._as_le_slice(memory)
1873            }
1874
1875            fn _as_le_slice<'a>(&self, all_of_memory: &'a [u8]) -> &'a [$i] {
1876                // See comments in `WasmList::get` for the panicking indexing
1877                let byte_size = self.len * mem::size_of::<$i>();
1878                let bytes = &all_of_memory[self.ptr..][..byte_size];
1879
1880                // The canonical ABI requires that everything is aligned to its
1881                // own size, so this should be an aligned array. Furthermore the
1882                // alignment of primitive integers for hosts should be smaller
1883                // than or equal to the size of the primitive itself, meaning
1884                // that a wasm canonical-abi-aligned list is also aligned for
1885                // the host. That should mean that the head/tail slices here are
1886                // empty.
1887                //
1888                // Also note that the `unsafe` here is needed since the type
1889                // we're aligning to isn't guaranteed to be valid, but in our
1890                // case it's just integers and bytes so this should be safe.
1891                unsafe {
1892                    let (head, body, tail) = bytes.align_to::<$i>();
1893                    assert!(head.is_empty() && tail.is_empty());
1894                    body
1895                }
1896            }
1897        }
1898    )*)
1899}
1900
1901raw_wasm_list_accessors! {
1902    i8 i16 i32 i64
1903    u8 u16 u32 u64
1904}
1905
1906// Note that this is similar to `ComponentType for str` except it can only be
1907// used for lifting, not lowering.
1908unsafe impl<T: ComponentType> ComponentType for WasmList<T> {
1909    type Lower = <[T] as ComponentType>::Lower;
1910
1911    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1912
1913    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1914        <[T] as ComponentType>::typecheck(ty, types)
1915    }
1916}
1917
1918unsafe impl<T: Lift> Lift for WasmList<T> {
1919    fn linear_lift_from_flat(
1920        cx: &mut LiftContext<'_>,
1921        ty: InterfaceType,
1922        src: &Self::Lower,
1923    ) -> Result<Self> {
1924        let elem = match ty {
1925            InterfaceType::List(i) => cx.types[i].element,
1926            _ => bad_type_info(),
1927        };
1928        let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
1929        WasmList::new(ptr, len, cx, elem)
1930    }
1931
1932    fn linear_lift_from_memory(
1933        cx: &mut LiftContext<'_>,
1934        ty: InterfaceType,
1935        bytes: &[u8],
1936    ) -> Result<Self> {
1937        let elem = match ty {
1938            InterfaceType::List(i) => cx.types[i].element,
1939            _ => bad_type_info(),
1940        };
1941        debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
1942        let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
1943        WasmList::new(ptr, len, cx, elem)
1944    }
1945}
1946
1947// =============================================================================
1948// HashMap<K, V> support for component model `map<K, V>`
1949//
1950// Maps are represented as `list<tuple<K, V>>` in the canonical ABI, so the
1951// lowered form is a (pointer, length) pair just like lists.
1952
1953fn map_abi<'a>(ty: InterfaceType, types: &'a ComponentTypes) -> &'a TypeMap {
1954    match ty {
1955        InterfaceType::Map(i) => &types[i],
1956        _ => bad_type_info(),
1957    }
1958}
1959
1960unsafe impl<K, V> ComponentType for HashMap<K, V>
1961where
1962    K: ComponentType,
1963    V: ComponentType,
1964{
1965    type Lower = [ValRaw; 2];
1966
1967    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
1968
1969    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
1970        TryHashMap::<K, V>::typecheck(ty, types)
1971    }
1972}
1973
1974unsafe impl<K, V> Lower for HashMap<K, V>
1975where
1976    K: Lower,
1977    V: Lower,
1978{
1979    fn linear_lower_to_flat<U>(
1980        &self,
1981        cx: &mut LowerContext<'_, U>,
1982        ty: InterfaceType,
1983        dst: &mut MaybeUninit<[ValRaw; 2]>,
1984    ) -> Result<()> {
1985        let map = map_abi(ty, &cx.types);
1986        let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?;
1987        lower_pointer_pair_to_flat(cx, dst, ptr, len);
1988        Ok(())
1989    }
1990
1991    fn linear_lower_to_memory<U>(
1992        &self,
1993        cx: &mut LowerContext<'_, U>,
1994        ty: InterfaceType,
1995        offset: usize,
1996    ) -> Result<()> {
1997        let map = map_abi(ty, &cx.types);
1998        debug_assert!(offset % (CanonicalAbiInfo::POINTER_PAIR.align32 as usize) == 0);
1999        let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?;
2000        lower_pointer_pair_to_memory(cx, offset, ptr, len);
2001        Ok(())
2002    }
2003}
2004
2005unsafe impl<K, V> Lift for HashMap<K, V>
2006where
2007    K: Lift + Eq + Hash,
2008    V: Lift,
2009{
2010    fn linear_lift_from_flat(
2011        cx: &mut LiftContext<'_>,
2012        ty: InterfaceType,
2013        src: &Self::Lower,
2014    ) -> Result<Self> {
2015        Ok(TryHashMap::<K, V>::linear_lift_from_flat(cx, ty, src)?.into())
2016    }
2017
2018    fn linear_lift_from_memory(
2019        cx: &mut LiftContext<'_>,
2020        ty: InterfaceType,
2021        bytes: &[u8],
2022    ) -> Result<Self> {
2023        Ok(TryHashMap::<K, V>::linear_lift_from_memory(cx, ty, bytes)?.into())
2024    }
2025}
2026
2027fn lower_map_iter<'a, K, V, U>(
2028    cx: &mut LowerContext<'_, U>,
2029    map: &TypeMap,
2030    len: usize,
2031    iter: impl Iterator<Item = (&'a K, &'a V)>,
2032) -> Result<(usize, usize)>
2033where
2034    K: Lower + 'a,
2035    V: Lower + 'a,
2036{
2037    let size = len
2038        .checked_mul(usize::try_from(map.entry_abi.size32)?)
2039        .ok_or_else(|| format_err!("size overflow copying a map"))?;
2040    let ptr = cx.realloc(0, 0, map.entry_abi.align32, size)?;
2041
2042    let mut entry_offset = ptr;
2043    for (key, value) in iter {
2044        // Keys are the first field in each entry tuple.
2045        <K as Lower>::linear_lower_to_memory(key, cx, map.key, entry_offset)?;
2046        // Values start at the precomputed value offset within the tuple.
2047        <V as Lower>::linear_lower_to_memory(
2048            value,
2049            cx,
2050            map.value,
2051            entry_offset + usize::try_from(map.value_offset32)?,
2052        )?;
2053        entry_offset += usize::try_from(map.entry_abi.size32)?;
2054    }
2055
2056    Ok((ptr, len))
2057}
2058
2059unsafe impl<K, V> ComponentType for TryHashMap<K, V>
2060where
2061    K: ComponentType,
2062    V: ComponentType,
2063{
2064    type Lower = [ValRaw; 2];
2065
2066    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::POINTER_PAIR;
2067
2068    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2069        match ty {
2070            InterfaceType::Map(t) => {
2071                let map_ty = &types.types[*t];
2072                K::typecheck(&map_ty.key, types)?;
2073                V::typecheck(&map_ty.value, types)?;
2074                Ok(())
2075            }
2076            other => bail!("expected `map` found `{}`", desc(other)),
2077        }
2078    }
2079}
2080
2081unsafe impl<K, V> Lower for TryHashMap<K, V>
2082where
2083    K: Lower,
2084    V: Lower,
2085{
2086    fn linear_lower_to_flat<U>(
2087        &self,
2088        cx: &mut LowerContext<'_, U>,
2089        ty: InterfaceType,
2090        dst: &mut MaybeUninit<[ValRaw; 2]>,
2091    ) -> Result<()> {
2092        let map = map_abi(ty, &cx.types);
2093        let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?;
2094        lower_pointer_pair_to_flat(cx, dst, ptr, len);
2095        Ok(())
2096    }
2097
2098    fn linear_lower_to_memory<U>(
2099        &self,
2100        cx: &mut LowerContext<'_, U>,
2101        ty: InterfaceType,
2102        offset: usize,
2103    ) -> Result<()> {
2104        let map = map_abi(ty, &cx.types);
2105        debug_assert!(offset % (CanonicalAbiInfo::POINTER_PAIR.align32 as usize) == 0);
2106        let (ptr, len) = lower_map_iter(cx, map, self.len(), self.iter())?;
2107        lower_pointer_pair_to_memory(cx, offset, ptr, len);
2108        Ok(())
2109    }
2110}
2111
2112unsafe impl<K, V> Lift for TryHashMap<K, V>
2113where
2114    K: Lift + Eq + Hash,
2115    V: Lift,
2116{
2117    fn linear_lift_from_flat(
2118        cx: &mut LiftContext<'_>,
2119        ty: InterfaceType,
2120        src: &Self::Lower,
2121    ) -> Result<Self> {
2122        let map = map_abi(ty, &cx.types);
2123        let (ptr, len) = lift_pointer_pair_from_flat(cx, src)?;
2124        lift_try_map(cx, map, ptr, len)
2125    }
2126
2127    fn linear_lift_from_memory(
2128        cx: &mut LiftContext<'_>,
2129        ty: InterfaceType,
2130        bytes: &[u8],
2131    ) -> Result<Self> {
2132        let map = map_abi(ty, &cx.types);
2133        debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2134        let (ptr, len) = lift_pointer_pair_from_memory(cx, bytes)?;
2135        lift_try_map(cx, map, ptr, len)
2136    }
2137}
2138
2139fn lift_try_map<K, V>(
2140    cx: &mut LiftContext<'_>,
2141    map: &TypeMap,
2142    ptr: usize,
2143    len: usize,
2144) -> Result<TryHashMap<K, V>>
2145where
2146    K: Lift + Eq + Hash,
2147    V: Lift,
2148{
2149    let mut result = TryHashMap::with_capacity(len)?;
2150
2151    match len
2152        .checked_mul(usize::try_from(map.entry_abi.size32)?)
2153        .and_then(|total| ptr.checked_add(total))
2154    {
2155        Some(n) if n <= cx.memory().len() => cx.consume_fuel_array(len, size_of::<(K, V)>())?,
2156        _ => bail!("map pointer/length out of bounds of memory"),
2157    }
2158    if ptr % (map.entry_abi.align32 as usize) != 0 {
2159        bail!("map pointer is not aligned");
2160    }
2161
2162    for i in 0..len {
2163        let entry_base = ptr + (i * usize::try_from(map.entry_abi.size32)?);
2164
2165        let key_bytes = &cx.memory()[entry_base..][..K::SIZE32];
2166        let key = K::linear_lift_from_memory(cx, map.key, key_bytes)?;
2167
2168        let value_bytes =
2169            &cx.memory()[entry_base + usize::try_from(map.value_offset32)?..][..V::SIZE32];
2170        let value = V::linear_lift_from_memory(cx, map.value, value_bytes)?;
2171
2172        result.insert(key, value)?;
2173    }
2174
2175    Ok(result)
2176}
2177
2178/// Verify that the given wasm type is a tuple with the expected fields in the right order.
2179fn typecheck_tuple(
2180    ty: &InterfaceType,
2181    types: &InstanceType<'_>,
2182    expected: &[fn(&InterfaceType, &InstanceType<'_>) -> Result<()>],
2183) -> Result<()> {
2184    match ty {
2185        InterfaceType::Tuple(t) => {
2186            let tuple = &types.types[*t];
2187            if tuple.types.len() != expected.len() {
2188                bail!(
2189                    "expected {}-tuple, found {}-tuple",
2190                    expected.len(),
2191                    tuple.types.len()
2192                );
2193            }
2194            for (ty, check) in tuple.types.iter().zip(expected) {
2195                check(ty, types)?;
2196            }
2197            Ok(())
2198        }
2199        other => bail!("expected `tuple` found `{}`", desc(other)),
2200    }
2201}
2202
2203/// Verify that the given wasm type is a record with the expected fields in the right order and with the right
2204/// names.
2205pub fn typecheck_record(
2206    ty: &InterfaceType,
2207    types: &InstanceType<'_>,
2208    expected: &[(&str, fn(&InterfaceType, &InstanceType<'_>) -> Result<()>)],
2209) -> Result<()> {
2210    match ty {
2211        InterfaceType::Record(index) => {
2212            let fields = &types.types[*index].fields;
2213
2214            if fields.len() != expected.len() {
2215                bail!(
2216                    "expected record of {} fields, found {} fields",
2217                    expected.len(),
2218                    fields.len()
2219                );
2220            }
2221
2222            for (field, &(name, check)) in fields.iter().zip(expected) {
2223                check(&field.ty, types)
2224                    .with_context(|| format!("type mismatch for field {name}"))?;
2225
2226                if field.name != name {
2227                    bail!("expected record field named {}, found {}", name, field.name);
2228                }
2229            }
2230
2231            Ok(())
2232        }
2233        other => bail!("expected `record` found `{}`", desc(other)),
2234    }
2235}
2236
2237/// Verify that the given wasm type is a variant with the expected cases in the right order and with the right
2238/// names.
2239pub fn typecheck_variant(
2240    ty: &InterfaceType,
2241    types: &InstanceType<'_>,
2242    expected: &[(
2243        &str,
2244        Option<fn(&InterfaceType, &InstanceType<'_>) -> Result<()>>,
2245    )],
2246) -> Result<()> {
2247    match ty {
2248        InterfaceType::Variant(index) => {
2249            let cases = &types.types[*index].cases;
2250
2251            if cases.len() != expected.len() {
2252                bail!(
2253                    "expected variant of {} cases, found {} cases",
2254                    expected.len(),
2255                    cases.len()
2256                );
2257            }
2258
2259            for ((case_name, case_ty), &(name, check)) in cases.iter().zip(expected) {
2260                if *case_name != name {
2261                    bail!("expected variant case named {name}, found {case_name}");
2262                }
2263
2264                match (check, case_ty) {
2265                    (Some(check), Some(ty)) => check(ty, types)
2266                        .with_context(|| format!("type mismatch for case {name}"))?,
2267                    (None, None) => {}
2268                    (Some(_), None) => {
2269                        bail!("case `{name}` has no type but one was expected")
2270                    }
2271                    (None, Some(_)) => {
2272                        bail!("case `{name}` has a type but none was expected")
2273                    }
2274                }
2275            }
2276
2277            Ok(())
2278        }
2279        other => bail!("expected `variant` found `{}`", desc(other)),
2280    }
2281}
2282
2283/// Verify that the given wasm type is a enum with the expected cases in the right order and with the right
2284/// names.
2285pub fn typecheck_enum(
2286    ty: &InterfaceType,
2287    types: &InstanceType<'_>,
2288    expected: &[&str],
2289) -> Result<()> {
2290    match ty {
2291        InterfaceType::Enum(index) => {
2292            let names = &types.types[*index].names;
2293
2294            if names.len() != expected.len() {
2295                bail!(
2296                    "expected enum of {} names, found {} names",
2297                    expected.len(),
2298                    names.len()
2299                );
2300            }
2301
2302            for (name, expected) in names.iter().zip(expected) {
2303                if name != expected {
2304                    bail!("expected enum case named {expected}, found {name}");
2305                }
2306            }
2307
2308            Ok(())
2309        }
2310        other => bail!("expected `enum` found `{}`", desc(other)),
2311    }
2312}
2313
2314/// Verify that the given wasm type is a flags type with the expected flags in the right order and with the right
2315/// names.
2316pub fn typecheck_flags(
2317    ty: &InterfaceType,
2318    types: &InstanceType<'_>,
2319    expected: &[&str],
2320) -> Result<()> {
2321    match ty {
2322        InterfaceType::Flags(index) => {
2323            let names = &types.types[*index].names;
2324
2325            if names.len() != expected.len() {
2326                bail!(
2327                    "expected flags type with {} names, found {} names",
2328                    expected.len(),
2329                    names.len()
2330                );
2331            }
2332
2333            for (name, expected) in names.iter().zip(expected) {
2334                if name != expected {
2335                    bail!("expected flag named {expected}, found {name}");
2336                }
2337            }
2338
2339            Ok(())
2340        }
2341        other => bail!("expected `flags` found `{}`", desc(other)),
2342    }
2343}
2344
2345/// Format the specified bitflags using the specified names for debugging
2346pub fn format_flags(bits: &[u32], names: &[&str], f: &mut fmt::Formatter) -> fmt::Result {
2347    f.write_str("(")?;
2348    let mut wrote = false;
2349    for (index, name) in names.iter().enumerate() {
2350        if ((bits[index / 32] >> (index % 32)) & 1) != 0 {
2351            if wrote {
2352                f.write_str("|")?;
2353            } else {
2354                wrote = true;
2355            }
2356
2357            f.write_str(name)?;
2358        }
2359    }
2360    f.write_str(")")
2361}
2362
2363unsafe impl<T> ComponentType for Option<T>
2364where
2365    T: ComponentType,
2366{
2367    type Lower = TupleLower<<u32 as ComponentType>::Lower, T::Lower>;
2368
2369    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[None, Some(T::ABI)]);
2370    const MAY_REQUIRE_REALLOC: bool = T::MAY_REQUIRE_REALLOC;
2371
2372    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2373        match ty {
2374            InterfaceType::Option(t) => T::typecheck(&types.types[*t].ty, types),
2375            other => bail!("expected `option` found `{}`", desc(other)),
2376        }
2377    }
2378}
2379
2380unsafe impl<T> ComponentVariant for Option<T>
2381where
2382    T: ComponentType,
2383{
2384    const CASES: &'static [Option<CanonicalAbiInfo>] = &[None, Some(T::ABI)];
2385}
2386
2387unsafe impl<T> Lower for Option<T>
2388where
2389    T: Lower,
2390{
2391    fn linear_lower_to_flat<U>(
2392        &self,
2393        cx: &mut LowerContext<'_, U>,
2394        ty: InterfaceType,
2395        dst: &mut MaybeUninit<Self::Lower>,
2396    ) -> Result<()> {
2397        let payload = match ty {
2398            InterfaceType::Option(ty) => cx.types[ty].ty,
2399            _ => bad_type_info(),
2400        };
2401        match self {
2402            None => {
2403                map_maybe_uninit!(dst.A1).write(ValRaw::i32(0));
2404                // Note that this is unsafe as we're writing an arbitrary
2405                // bit-pattern to an arbitrary type, but part of the unsafe
2406                // contract of the `ComponentType` trait is that we can assign
2407                // any bit-pattern. By writing all zeros here we're ensuring
2408                // that the core wasm arguments this translates to will all be
2409                // zeros (as the canonical ABI requires).
2410                unsafe {
2411                    map_maybe_uninit!(dst.A2).as_mut_ptr().write_bytes(0u8, 1);
2412                }
2413            }
2414            Some(val) => {
2415                map_maybe_uninit!(dst.A1).write(ValRaw::i32(1));
2416                val.linear_lower_to_flat(cx, payload, map_maybe_uninit!(dst.A2))?;
2417            }
2418        }
2419        Ok(())
2420    }
2421
2422    fn linear_lower_to_memory<U>(
2423        &self,
2424        cx: &mut LowerContext<'_, U>,
2425        ty: InterfaceType,
2426        offset: usize,
2427    ) -> Result<()> {
2428        debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2429        let payload = match ty {
2430            InterfaceType::Option(ty) => cx.types[ty].ty,
2431            _ => bad_type_info(),
2432        };
2433        match self {
2434            None => {
2435                cx.get::<1>(offset)[0] = 0;
2436            }
2437            Some(val) => {
2438                cx.get::<1>(offset)[0] = 1;
2439                val.linear_lower_to_memory(
2440                    cx,
2441                    payload,
2442                    offset + (Self::INFO.payload_offset32 as usize),
2443                )?;
2444            }
2445        }
2446        Ok(())
2447    }
2448}
2449
2450unsafe impl<T> Lift for Option<T>
2451where
2452    T: Lift,
2453{
2454    fn linear_lift_from_flat(
2455        cx: &mut LiftContext<'_>,
2456        ty: InterfaceType,
2457        src: &Self::Lower,
2458    ) -> Result<Self> {
2459        let payload = match ty {
2460            InterfaceType::Option(ty) => cx.types[ty].ty,
2461            _ => bad_type_info(),
2462        };
2463        Ok(match src.A1.get_i32() {
2464            0 => None,
2465            1 => Some(T::linear_lift_from_flat(cx, payload, &src.A2)?),
2466            _ => bail!("invalid option discriminant"),
2467        })
2468    }
2469
2470    fn linear_lift_from_memory(
2471        cx: &mut LiftContext<'_>,
2472        ty: InterfaceType,
2473        bytes: &[u8],
2474    ) -> Result<Self> {
2475        debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2476        let payload_ty = match ty {
2477            InterfaceType::Option(ty) => cx.types[ty].ty,
2478            _ => bad_type_info(),
2479        };
2480        let discrim = bytes[0];
2481        let payload = &bytes[Self::INFO.payload_offset32 as usize..];
2482        match discrim {
2483            0 => Ok(None),
2484            1 => Ok(Some(T::linear_lift_from_memory(cx, payload_ty, payload)?)),
2485            _ => bail!("invalid option discriminant"),
2486        }
2487    }
2488}
2489
2490#[derive(Clone, Copy)]
2491#[repr(C)]
2492pub struct ResultLower<T: Copy, E: Copy> {
2493    tag: ValRaw,
2494    payload: ResultLowerPayload<T, E>,
2495}
2496
2497#[derive(Clone, Copy)]
2498#[repr(C)]
2499union ResultLowerPayload<T: Copy, E: Copy> {
2500    ok: T,
2501    err: E,
2502}
2503
2504unsafe impl<T, E> ComponentType for Result<T, E>
2505where
2506    T: ComponentType,
2507    E: ComponentType,
2508{
2509    type Lower = ResultLower<T::Lower, E::Lower>;
2510
2511    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::variant_static(&[Some(T::ABI), Some(E::ABI)]);
2512    const MAY_REQUIRE_REALLOC: bool = T::MAY_REQUIRE_REALLOC || E::MAY_REQUIRE_REALLOC;
2513
2514    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2515        match ty {
2516            InterfaceType::Result(r) => {
2517                let result = &types.types[*r];
2518                match &result.ok {
2519                    Some(ty) => T::typecheck(ty, types)?,
2520                    None if T::IS_RUST_UNIT_TYPE => {}
2521                    None => bail!("expected no `ok` type"),
2522                }
2523                match &result.err {
2524                    Some(ty) => E::typecheck(ty, types)?,
2525                    None if E::IS_RUST_UNIT_TYPE => {}
2526                    None => bail!("expected no `err` type"),
2527                }
2528                Ok(())
2529            }
2530            other => bail!("expected `result` found `{}`", desc(other)),
2531        }
2532    }
2533}
2534
2535/// Lowers the payload of a variant into the storage for the entire payload,
2536/// handling writing zeros at the end of the representation if this payload is
2537/// smaller than the entire flat representation.
2538///
2539/// * `payload` - the flat storage space for the entire payload of the variant
2540/// * `typed_payload` - projection from the payload storage space to the
2541///   individual storage space for this variant.
2542/// * `lower` - lowering operation used to initialize the `typed_payload` return
2543///   value.
2544///
2545/// For more information on this se the comments in the `Lower for Result`
2546/// implementation below.
2547pub unsafe fn lower_payload<P, T>(
2548    payload: &mut MaybeUninit<P>,
2549    typed_payload: impl FnOnce(&mut MaybeUninit<P>) -> &mut MaybeUninit<T>,
2550    lower: impl FnOnce(&mut MaybeUninit<T>) -> Result<()>,
2551) -> Result<()> {
2552    let typed = typed_payload(payload);
2553    lower(typed)?;
2554
2555    let typed_len = unsafe { storage_as_slice(typed).len() };
2556    let payload = unsafe { storage_as_slice_mut(payload) };
2557    for slot in payload[typed_len..].iter_mut() {
2558        slot.write(ValRaw::u64(0));
2559    }
2560    Ok(())
2561}
2562
2563unsafe impl<T, E> ComponentVariant for Result<T, E>
2564where
2565    T: ComponentType,
2566    E: ComponentType,
2567{
2568    const CASES: &'static [Option<CanonicalAbiInfo>] = &[Some(T::ABI), Some(E::ABI)];
2569}
2570
2571unsafe impl<T, E> Lower for Result<T, E>
2572where
2573    T: Lower,
2574    E: Lower,
2575{
2576    fn linear_lower_to_flat<U>(
2577        &self,
2578        cx: &mut LowerContext<'_, U>,
2579        ty: InterfaceType,
2580        dst: &mut MaybeUninit<Self::Lower>,
2581    ) -> Result<()> {
2582        let (ok, err) = match ty {
2583            InterfaceType::Result(ty) => {
2584                let ty = &cx.types[ty];
2585                (ty.ok, ty.err)
2586            }
2587            _ => bad_type_info(),
2588        };
2589
2590        // This implementation of `Lower::lower`, if you're reading these from
2591        // the top of this file, is the first location that the "join" logic of
2592        // the component model's canonical ABI encountered. The rough problem is
2593        // that let's say we have a component model type of the form:
2594        //
2595        //      (result u64 (error (tuple f32 u16)))
2596        //
2597        // The flat representation of this is actually pretty tricky. Currently
2598        // it is:
2599        //
2600        //      i32 i64 i32
2601        //
2602        // The first `i32` is the discriminant for the `result`, and the payload
2603        // is represented by `i64 i32`. The "ok" variant will only use the `i64`
2604        // and the "err" variant will use both `i64` and `i32`.
2605        //
2606        // In the "ok" variant the first issue is encountered. The size of one
2607        // variant may not match the size of the other variants. All variants
2608        // start at the "front" but when lowering a type we need to be sure to
2609        // initialize the later variants (lest we leak random host memory into
2610        // the guest module). Due to how the `Lower` type is represented as a
2611        // `union` of all the variants what ends up happening here is that
2612        // internally within the `lower_payload` after the typed payload is
2613        // lowered the remaining bits of the payload that weren't initialized
2614        // are all set to zero. This will guarantee that we'll write to all the
2615        // slots for each variant.
2616        //
2617        // The "err" variant encounters the second issue, however, which is that
2618        // the flat representation for each type may differ between payloads. In
2619        // the "ok" arm an `i64` is written, but the `lower` implementation for
2620        // the "err" arm will write an `f32` and then an `i32`. For this
2621        // implementation of `lower` to be valid the `f32` needs to get inflated
2622        // to an `i64` with zero-padding in the upper bits. What may be
2623        // surprising, however, is that none of this is handled in this file.
2624        // This implementation looks like it's blindly deferring to `E::lower`
2625        // and hoping it does the right thing.
2626        //
2627        // In reality, however, the correctness of variant lowering relies on
2628        // two subtle details of the `ValRaw` implementation in Wasmtime:
2629        //
2630        // 1. First the `ValRaw` value always contains little-endian values.
2631        //    This means that if a `u32` is written, a `u64` is read, and then
2632        //    the `u64` has its upper bits truncated the original value will
2633        //    always be retained. This is primarily here for big-endian
2634        //    platforms where if it weren't little endian then the opposite
2635        //    would occur and the wrong value would be read.
2636        //
2637        // 2. Second, and perhaps even more subtly, the `ValRaw` constructors
2638        //    for 32-bit types actually always initialize 64-bits of the
2639        //    `ValRaw`. In the component model flat ABI only 32 and 64-bit types
2640        //    are used so 64-bits is big enough to contain everything. This
2641        //    means that when a `ValRaw` is written into the destination it will
2642        //    always, whether it's needed or not, be "ready" to get extended up
2643        //    to 64-bits.
2644        //
2645        // Put together these two subtle guarantees means that all `Lower`
2646        // implementations can be written "naturally" as one might naively
2647        // expect. Variants will, on each arm, zero out remaining fields and all
2648        // writes to the flat representation will automatically be 64-bit writes
2649        // meaning that if the value is read as a 64-bit value, which isn't
2650        // known at the time of the write, it'll still be correct.
2651        match self {
2652            Ok(e) => {
2653                map_maybe_uninit!(dst.tag).write(ValRaw::i32(0));
2654                unsafe {
2655                    lower_payload(
2656                        map_maybe_uninit!(dst.payload),
2657                        |payload| map_maybe_uninit!(payload.ok),
2658                        |dst| match ok {
2659                            Some(ok) => e.linear_lower_to_flat(cx, ok, dst),
2660                            None => Ok(()),
2661                        },
2662                    )
2663                }
2664            }
2665            Err(e) => {
2666                map_maybe_uninit!(dst.tag).write(ValRaw::i32(1));
2667                unsafe {
2668                    lower_payload(
2669                        map_maybe_uninit!(dst.payload),
2670                        |payload| map_maybe_uninit!(payload.err),
2671                        |dst| match err {
2672                            Some(err) => e.linear_lower_to_flat(cx, err, dst),
2673                            None => Ok(()),
2674                        },
2675                    )
2676                }
2677            }
2678        }
2679    }
2680
2681    fn linear_lower_to_memory<U>(
2682        &self,
2683        cx: &mut LowerContext<'_, U>,
2684        ty: InterfaceType,
2685        offset: usize,
2686    ) -> Result<()> {
2687        let (ok, err) = match ty {
2688            InterfaceType::Result(ty) => {
2689                let ty = &cx.types[ty];
2690                (ty.ok, ty.err)
2691            }
2692            _ => bad_type_info(),
2693        };
2694        debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
2695        let payload_offset = Self::INFO.payload_offset32 as usize;
2696        match self {
2697            Ok(e) => {
2698                cx.get::<1>(offset)[0] = 0;
2699                if let Some(ok) = ok {
2700                    e.linear_lower_to_memory(cx, ok, offset + payload_offset)?;
2701                }
2702            }
2703            Err(e) => {
2704                cx.get::<1>(offset)[0] = 1;
2705                if let Some(err) = err {
2706                    e.linear_lower_to_memory(cx, err, offset + payload_offset)?;
2707                }
2708            }
2709        }
2710        Ok(())
2711    }
2712}
2713
2714unsafe impl<T, E> Lift for Result<T, E>
2715where
2716    T: Lift,
2717    E: Lift,
2718{
2719    #[inline]
2720    fn linear_lift_from_flat(
2721        cx: &mut LiftContext<'_>,
2722        ty: InterfaceType,
2723        src: &Self::Lower,
2724    ) -> Result<Self> {
2725        let (ok, err) = match ty {
2726            InterfaceType::Result(ty) => {
2727                let ty = &cx.types[ty];
2728                (ty.ok, ty.err)
2729            }
2730            _ => bad_type_info(),
2731        };
2732        // Note that this implementation specifically isn't trying to actually
2733        // reinterpret or alter the bits of `lower` depending on which variant
2734        // we're lifting. This ends up all working out because the value is
2735        // stored in little-endian format.
2736        //
2737        // When stored in little-endian format the `{T,E}::Lower`, when each
2738        // individual `ValRaw` is read, means that if an i64 value, extended
2739        // from an i32 value, was stored then when the i32 value is read it'll
2740        // automatically ignore the upper bits.
2741        //
2742        // This "trick" allows us to seamlessly pass through the `Self::Lower`
2743        // representation into the lifting/lowering without trying to handle
2744        // "join"ed types as per the canonical ABI. It just so happens that i64
2745        // bits will naturally be reinterpreted as f64. Additionally if the
2746        // joined type is i64 but only the lower bits are read that's ok and we
2747        // don't need to validate the upper bits.
2748        //
2749        // This is largely enabled by WebAssembly/component-model#35 where no
2750        // validation needs to be performed for ignored bits and bytes here.
2751        Ok(match src.tag.get_i32() {
2752            0 => Ok(unsafe { lift_option(cx, ok, &src.payload.ok)? }),
2753            1 => Err(unsafe { lift_option(cx, err, &src.payload.err)? }),
2754            _ => bail!("invalid expected discriminant"),
2755        })
2756    }
2757
2758    #[inline]
2759    fn linear_lift_from_memory(
2760        cx: &mut LiftContext<'_>,
2761        ty: InterfaceType,
2762        bytes: &[u8],
2763    ) -> Result<Self> {
2764        debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2765        let discrim = bytes[0];
2766        let payload = &bytes[Self::INFO.payload_offset32 as usize..];
2767        let (ok, err) = match ty {
2768            InterfaceType::Result(ty) => {
2769                let ty = &cx.types[ty];
2770                (ty.ok, ty.err)
2771            }
2772            _ => bad_type_info(),
2773        };
2774        match discrim {
2775            0 => Ok(Ok(load_option(cx, ok, &payload[..T::SIZE32])?)),
2776            1 => Ok(Err(load_option(cx, err, &payload[..E::SIZE32])?)),
2777            _ => bail!("invalid expected discriminant"),
2778        }
2779    }
2780}
2781
2782fn lift_option<T>(cx: &mut LiftContext<'_>, ty: Option<InterfaceType>, src: &T::Lower) -> Result<T>
2783where
2784    T: Lift,
2785{
2786    match ty {
2787        Some(ty) => T::linear_lift_from_flat(cx, ty, src),
2788        None => Ok(empty_lift()),
2789    }
2790}
2791
2792fn load_option<T>(cx: &mut LiftContext<'_>, ty: Option<InterfaceType>, bytes: &[u8]) -> Result<T>
2793where
2794    T: Lift,
2795{
2796    match ty {
2797        Some(ty) => T::linear_lift_from_memory(cx, ty, bytes),
2798        None => Ok(empty_lift()),
2799    }
2800}
2801
2802fn empty_lift<T>() -> T
2803where
2804    T: Lift,
2805{
2806    assert!(T::IS_RUST_UNIT_TYPE);
2807    assert_eq!(mem::size_of::<T>(), 0);
2808    unsafe { MaybeUninit::uninit().assume_init() }
2809}
2810
2811/// Helper structure to define `Lower` for tuples below.
2812///
2813/// Uses default type parameters to have fields be zero-sized and not present
2814/// in memory for smaller tuple values.
2815#[expect(non_snake_case, reason = "more amenable to macro-generated code")]
2816#[doc(hidden)]
2817#[derive(Clone, Copy)]
2818#[repr(C)]
2819pub struct TupleLower<
2820    T1 = (),
2821    T2 = (),
2822    T3 = (),
2823    T4 = (),
2824    T5 = (),
2825    T6 = (),
2826    T7 = (),
2827    T8 = (),
2828    T9 = (),
2829    T10 = (),
2830    T11 = (),
2831    T12 = (),
2832    T13 = (),
2833    T14 = (),
2834    T15 = (),
2835    T16 = (),
2836    T17 = (),
2837> {
2838    // NB: these names match the names in `for_each_function_signature!`
2839    A1: T1,
2840    A2: T2,
2841    A3: T3,
2842    A4: T4,
2843    A5: T5,
2844    A6: T6,
2845    A7: T7,
2846    A8: T8,
2847    A9: T9,
2848    A10: T10,
2849    A11: T11,
2850    A12: T12,
2851    A13: T13,
2852    A14: T14,
2853    A15: T15,
2854    A16: T16,
2855    A17: T17,
2856    _align_tuple_lower0_correctly: [ValRaw; 0],
2857}
2858
2859macro_rules! impl_component_ty_for_tuples {
2860    ($n:tt $($t:ident)*) => {
2861        #[allow(non_snake_case, reason = "macro-generated code")]
2862        unsafe impl<$($t,)*> ComponentType for ($($t,)*)
2863            where $($t: ComponentType),*
2864        {
2865            type Lower = TupleLower<$($t::Lower),*>;
2866
2867            const ABI: CanonicalAbiInfo = CanonicalAbiInfo::record_static(&[
2868                $($t::ABI),*
2869            ]);
2870            const MAY_REQUIRE_REALLOC: bool = false $(|| $t::MAY_REQUIRE_REALLOC)*;
2871
2872            const IS_RUST_UNIT_TYPE: bool = {
2873                let mut _is_unit = true;
2874                $(
2875                    let _anything_to_bind_the_macro_variable = $t::IS_RUST_UNIT_TYPE;
2876                    _is_unit = false;
2877                )*
2878                _is_unit
2879            };
2880
2881            fn typecheck(
2882                ty: &InterfaceType,
2883                types: &InstanceType<'_>,
2884            ) -> Result<()> {
2885                typecheck_tuple(ty, types, &[$($t::typecheck),*])
2886            }
2887        }
2888
2889        #[allow(non_snake_case, reason = "macro-generated code")]
2890        unsafe impl<$($t,)*> Lower for ($($t,)*)
2891            where $($t: Lower),*
2892        {
2893            fn linear_lower_to_flat<U>(
2894                &self,
2895                cx: &mut LowerContext<'_, U>,
2896                ty: InterfaceType,
2897                _dst: &mut MaybeUninit<Self::Lower>,
2898            ) -> Result<()> {
2899                let types = match ty {
2900                    InterfaceType::Tuple(t) => &cx.types[t].types,
2901                    _ => bad_type_info(),
2902                };
2903                let ($($t,)*) = self;
2904                let mut _types = types.iter();
2905                $(
2906                    let ty = *_types.next().unwrap_or_else(bad_type_info);
2907                    $t.linear_lower_to_flat(cx, ty, map_maybe_uninit!(_dst.$t))?;
2908                )*
2909                Ok(())
2910            }
2911
2912            fn linear_lower_to_memory<U>(
2913                &self,
2914                cx: &mut LowerContext<'_, U>,
2915                ty: InterfaceType,
2916                mut _offset: usize,
2917            ) -> Result<()> {
2918                debug_assert!(_offset % (Self::ALIGN32 as usize) == 0);
2919                let types = match ty {
2920                    InterfaceType::Tuple(t) => &cx.types[t].types,
2921                    _ => bad_type_info(),
2922                };
2923                let ($($t,)*) = self;
2924                let mut _types = types.iter();
2925                $(
2926                    let ty = *_types.next().unwrap_or_else(bad_type_info);
2927                    $t.linear_lower_to_memory(cx, ty, $t::ABI.next_field32_size(&mut _offset))?;
2928                )*
2929                Ok(())
2930            }
2931        }
2932
2933        #[allow(non_snake_case, reason = "macro-generated code")]
2934        unsafe impl<$($t,)*> Lift for ($($t,)*)
2935            where $($t: Lift),*
2936        {
2937            #[inline]
2938            fn linear_lift_from_flat(cx: &mut LiftContext<'_>, ty: InterfaceType, _src: &Self::Lower) -> Result<Self> {
2939                let types = match ty {
2940                    InterfaceType::Tuple(t) => &cx.types[t].types,
2941                    _ => bad_type_info(),
2942                };
2943                let mut _types = types.iter();
2944                Ok(($(
2945                    $t::linear_lift_from_flat(
2946                        cx,
2947                        *_types.next().unwrap_or_else(bad_type_info),
2948                        &_src.$t,
2949                    )?,
2950                )*))
2951            }
2952
2953            #[inline]
2954            fn linear_lift_from_memory(cx: &mut LiftContext<'_>, ty: InterfaceType, bytes: &[u8]) -> Result<Self> {
2955                debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
2956                let types = match ty {
2957                    InterfaceType::Tuple(t) => &cx.types[t].types,
2958                    _ => bad_type_info(),
2959                };
2960                let mut _types = types.iter();
2961                let mut _offset = 0;
2962                $(
2963                    let ty = *_types.next().unwrap_or_else(bad_type_info);
2964                    let $t = $t::linear_lift_from_memory(cx, ty, &bytes[$t::ABI.next_field32_size(&mut _offset)..][..$t::SIZE32])?;
2965                )*
2966                Ok(($($t,)*))
2967            }
2968        }
2969
2970        #[allow(non_snake_case, reason = "macro-generated code")]
2971        unsafe impl<$($t,)*> ComponentNamedList for ($($t,)*)
2972            where $($t: ComponentType),*
2973        {}
2974    };
2975}
2976
2977for_each_function_signature!(impl_component_ty_for_tuples);
2978
2979unsafe impl<T, const N: usize> ComponentType for [T; N]
2980where
2981    T: ComponentType,
2982{
2983    type Lower = [T::Lower; N];
2984
2985    const ABI: CanonicalAbiInfo = CanonicalAbiInfo::fixed_length_list_static(&T::ABI, N);
2986
2987    fn typecheck(ty: &InterfaceType, types: &InstanceType<'_>) -> Result<()> {
2988        match ty {
2989            InterfaceType::FixedLengthList(t) => {
2990                let list = &types.types[*t];
2991                match usize::try_from(list.size) {
2992                    Ok(n) if n == N => {}
2993                    _ => bail!("expected `list<_, {}>` found `list<_, {N}>`", list.size),
2994                }
2995                T::typecheck(&list.element, types)
2996            }
2997            other => bail!("expected `list<_, {N}>` found `{}`", desc(other)),
2998        }
2999    }
3000}
3001
3002unsafe impl<T, const N: usize> Lower for [T; N]
3003where
3004    T: Lower,
3005{
3006    fn linear_lower_to_flat<U>(
3007        &self,
3008        cx: &mut LowerContext<'_, U>,
3009        ty: InterfaceType,
3010        dst: &mut MaybeUninit<Self::Lower>,
3011    ) -> Result<()> {
3012        let element = match ty {
3013            InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3014            _ => bad_type_info(),
3015        };
3016        for (i, val) in self.iter().enumerate() {
3017            val.linear_lower_to_flat(cx, element, map_maybe_uninit!(dst[i]))?;
3018        }
3019        Ok(())
3020    }
3021
3022    fn linear_lower_to_memory<U>(
3023        &self,
3024        cx: &mut LowerContext<'_, U>,
3025        ty: InterfaceType,
3026        offset: usize,
3027    ) -> Result<()> {
3028        debug_assert!(offset % (Self::ALIGN32 as usize) == 0);
3029        let element = match ty {
3030            InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3031            _ => bad_type_info(),
3032        };
3033        for (i, val) in self.iter().enumerate() {
3034            val.linear_lower_to_memory(cx, element, offset + i * T::SIZE32)?;
3035        }
3036        Ok(())
3037    }
3038}
3039
3040unsafe impl<T, const N: usize> Lift for [T; N]
3041where
3042    T: Lift + Sized,
3043{
3044    fn linear_lift_from_flat(
3045        cx: &mut LiftContext<'_>,
3046        ty: InterfaceType,
3047        src: &Self::Lower,
3048    ) -> Result<Self> {
3049        let element = match ty {
3050            InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3051            _ => bad_type_info(),
3052        };
3053        array_try_from_fn(|n| T::linear_lift_from_flat(cx, element, &src[n]))
3054    }
3055
3056    fn linear_lift_from_memory(
3057        cx: &mut LiftContext<'_>,
3058        ty: InterfaceType,
3059        bytes: &[u8],
3060    ) -> Result<Self> {
3061        debug_assert!((bytes.as_ptr() as usize) % (Self::ALIGN32 as usize) == 0);
3062        let element = match ty {
3063            InterfaceType::FixedLengthList(ty) => cx.types[ty].element,
3064            _ => bad_type_info(),
3065        };
3066        let mut offset = 0;
3067        array_try_from_fn(|_n| {
3068            let res = T::linear_lift_from_memory(cx, element, &bytes[offset..offset + T::SIZE32]);
3069            offset += T::SIZE32;
3070            res
3071        })
3072    }
3073}
3074
3075pub fn desc(ty: &InterfaceType) -> &'static str {
3076    match ty {
3077        InterfaceType::U8 => "u8",
3078        InterfaceType::S8 => "s8",
3079        InterfaceType::U16 => "u16",
3080        InterfaceType::S16 => "s16",
3081        InterfaceType::U32 => "u32",
3082        InterfaceType::S32 => "s32",
3083        InterfaceType::U64 => "u64",
3084        InterfaceType::S64 => "s64",
3085        InterfaceType::Float32 => "f32",
3086        InterfaceType::Float64 => "f64",
3087        InterfaceType::Bool => "bool",
3088        InterfaceType::Char => "char",
3089        InterfaceType::String => "string",
3090        InterfaceType::List(_) => "list",
3091        InterfaceType::Tuple(_) => "tuple",
3092        InterfaceType::Option(_) => "option",
3093        InterfaceType::Result(_) => "result",
3094
3095        InterfaceType::Record(_) => "record",
3096        InterfaceType::Variant(_) => "variant",
3097        InterfaceType::Flags(_) => "flags",
3098        InterfaceType::Enum(_) => "enum",
3099        InterfaceType::Own(_) => "owned resource",
3100        InterfaceType::Borrow(_) => "borrowed resource",
3101        InterfaceType::Future(_) => "future",
3102        InterfaceType::Stream(_) => "stream",
3103        InterfaceType::ErrorContext(_) => "error-context",
3104        InterfaceType::Map(_) => "map",
3105        InterfaceType::FixedLengthList(_) => "list<_, N>",
3106    }
3107}
3108
3109#[cold]
3110#[doc(hidden)]
3111pub fn bad_type_info<T>() -> T {
3112    // NB: should consider something like `unreachable_unchecked` here if this
3113    // becomes a performance bottleneck at some point, but that also comes with
3114    // a tradeoff of propagating a lot of unsafety, so it may not be worth it.
3115    panic!("bad type information detected");
3116}