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