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