wasmi/func/
typed_func.rs

1use super::{into_func::WasmTyList, Func};
2use crate::{
3    core::UntypedVal,
4    engine::{CallParams, CallResults},
5    AsContext,
6    AsContextMut,
7    Error,
8    TypedResumableCall,
9};
10use core::{fmt, fmt::Debug, marker::PhantomData};
11
12/// A typed [`Func`] instance.
13///
14/// # Note
15///
16/// This allows a more efficient execution by avoiding type checks
17/// upon function call since those type checks are performed upon [`TypedFunc`]
18/// construction and enforced by the Rust type system.
19///
20/// Use [`TypedFunc`] instead of [`Func`] if possible.
21#[repr(transparent)]
22pub struct TypedFunc<Params, Results> {
23    /// The parameter and result typed encoded in Rust type system.
24    signature: PhantomData<fn(Params) -> Results>,
25    /// The underlying [`Func`] instance.
26    func: Func,
27}
28
29impl<Params, Results> Debug for TypedFunc<Params, Results> {
30    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
31        f.debug_struct("TypedFunc")
32            .field("signature", &self.signature)
33            .field("func", &self.func)
34            .finish()
35    }
36}
37
38impl<Params, Results> Copy for TypedFunc<Params, Results> {}
39
40impl<Params, Results> Clone for TypedFunc<Params, Results> {
41    fn clone(&self) -> TypedFunc<Params, Results> {
42        *self
43    }
44}
45
46impl<Params, Results> TypedFunc<Params, Results> {
47    /// Returns the underlying [`Func`].
48    ///
49    /// # Note
50    ///
51    /// This loses the static type information in the process.
52    pub fn func(&self) -> &Func {
53        &self.func
54    }
55}
56
57impl<Params, Results> TypedFunc<Params, Results>
58where
59    Params: WasmParams,
60    Results: WasmResults,
61{
62    /// Creates a new [`TypedFunc`] for the given [`Func`] using the static typing.
63    ///
64    /// # Errors
65    ///
66    /// If the provided static types `Params` and `Results` for the parameters
67    /// and result types of `func` mismatch the signature of `func`.
68    pub(crate) fn new(ctx: impl AsContext, func: Func) -> Result<Self, Error> {
69        let func_type = func.ty(&ctx);
70        let (actual_params, actual_results) = (
71            <Params as WasmTyList>::types(),
72            <Results as WasmTyList>::types(),
73        );
74        func_type.match_params(actual_params.as_ref())?;
75        func_type.match_results(actual_results.as_ref(), true)?;
76        Ok(Self {
77            signature: PhantomData,
78            func,
79        })
80    }
81
82    /// Calls this Wasm or host function with the specified parameters.
83    ///
84    /// Returns either the results of the call, or a [`Error`] if one happened.
85    ///
86    /// For more information, see the [`Func::typed`] and [`Func::call`]
87    /// documentation.
88    ///
89    /// # Panics
90    ///
91    /// Panics if `ctx` does not own this [`TypedFunc`].
92    ///
93    /// # Errors
94    ///
95    /// If the execution of the called Wasm function traps.
96    pub fn call(&self, mut ctx: impl AsContextMut, params: Params) -> Result<Results, Error> {
97        // Note: Cloning an [`Engine`] is intentionally a cheap operation.
98        ctx.as_context().store.engine().clone().execute_func(
99            ctx.as_context_mut(),
100            &self.func,
101            params,
102            <CallResultsTuple<Results>>::default(),
103        )
104    }
105
106    /// Calls this Wasm or host function with the specified parameters.
107    ///
108    /// Returns a resumable handle to the function invocation upon
109    /// encountering host errors with which it is possible to handle
110    /// the error and continue the execution as if no error occurred.
111    ///
112    /// # Note
113    ///
114    /// This is a non-standard WebAssembly API and might not be available
115    /// at other WebAssembly engines. Please be aware that depending on this
116    /// feature might mean a lock-in to Wasmi for users.
117    ///
118    /// # Errors
119    ///
120    /// If the function returned a [`Error`] originating from WebAssembly.
121    pub fn call_resumable(
122        &self,
123        mut ctx: impl AsContextMut,
124        params: Params,
125    ) -> Result<TypedResumableCall<Results>, Error> {
126        // Note: Cloning an [`Engine`] is intentionally a cheap operation.
127        ctx.as_context()
128            .store
129            .engine()
130            .clone()
131            .execute_func_resumable(
132                ctx.as_context_mut(),
133                &self.func,
134                params,
135                <CallResultsTuple<Results>>::default(),
136            )
137            .map(TypedResumableCall::new)
138    }
139}
140
141impl<Params> CallParams for Params
142where
143    Params: WasmParams,
144{
145    type Params = <Params as WasmTyList>::ValuesIter;
146
147    #[inline]
148    fn call_params(self) -> Self::Params {
149        <Params as WasmTyList>::values(self).into_iter()
150    }
151}
152
153/// Wrapper around the result tuple types of a [`TypedFunc`].
154///
155/// # Note
156///
157/// This type is a utility in order to provide an efficient implementation
158/// of the [`CallResults`] trait required for executing the [`TypedFunc`]
159/// via the [`Engine`].
160///
161/// [`Engine`]: [`crate::Engine`].
162pub struct CallResultsTuple<Results> {
163    _marker: PhantomData<fn() -> Results>,
164}
165
166impl<Results> Default for CallResultsTuple<Results> {
167    fn default() -> Self {
168        Self {
169            _marker: PhantomData,
170        }
171    }
172}
173impl<Results> Copy for CallResultsTuple<Results> {}
174impl<Results> Clone for CallResultsTuple<Results> {
175    fn clone(&self) -> Self {
176        *self
177    }
178}
179
180impl<Results> CallResults for CallResultsTuple<Results>
181where
182    Results: WasmResults,
183{
184    type Results = Results;
185
186    fn len_results(&self) -> usize {
187        <Results as WasmTyList>::LEN
188    }
189
190    fn call_results(self, results: &[UntypedVal]) -> Self::Results {
191        <Results as WasmTyList>::from_values(results)
192            .expect("unable to construct typed results from call results")
193    }
194}
195
196/// The typed parameters of a [`TypedFunc`].
197pub trait WasmParams: WasmTyList {}
198impl<T> WasmParams for T where T: WasmTyList {}
199
200/// The typed results of a [`TypedFunc`].
201pub trait WasmResults: WasmTyList {}
202impl<T> WasmResults for T where T: WasmTyList {}