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