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