wasmtime/runtime/component/func/
typed.rs

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