wasmer/utils/native/
typed_func.rs

1//! Native Functions.
2//!
3//! This module creates the helper [`TypedFunction`] that let us call WebAssembly
4//! functions with the native ABI, that is:
5//!
6//! ```ignore
7//! let add_one = instance.exports.get_function("function_name")?;
8//! let add_one_native: TypedFunction<i32, i32> = add_one.native().unwrap();
9//! ```
10#[cfg(feature = "experimental-async")]
11use crate::AsStoreAsync;
12use crate::{
13    AsStoreMut, BackendStore, FromToNativeWasmType, Function, NativeWasmTypeInto, RuntimeError,
14    WasmTypeList, store::AsStoreRef,
15};
16use std::future::Future;
17use std::marker::PhantomData;
18use wasmer_types::RawValue;
19
20/// A WebAssembly function that can be called natively
21/// (using the Native ABI).
22#[derive(Clone, Debug)]
23pub struct TypedFunction<Args, Rets> {
24    pub(crate) func: Function,
25    _phantom: PhantomData<fn(Args) -> Rets>,
26}
27
28unsafe impl<Args, Rets> Send for TypedFunction<Args, Rets> {}
29unsafe impl<Args, Rets> Sync for TypedFunction<Args, Rets> {}
30
31impl<Args, Rets> TypedFunction<Args, Rets>
32where
33    Args: WasmTypeList,
34    Rets: WasmTypeList,
35{
36    #[allow(dead_code)]
37    pub(crate) fn new(_store: &impl AsStoreRef, func: Function) -> Self {
38        Self {
39            func,
40            _phantom: PhantomData,
41        }
42    }
43
44    pub(crate) fn into_function(self) -> Function {
45        self.func
46    }
47}
48
49macro_rules! impl_native_traits {
50    (  $( $x:ident ),* ) => {
51        paste::paste!{
52        #[allow(unused_parens, non_snake_case)]
53        impl<$( $x , )* Rets> TypedFunction<( $( $x ),* ), Rets>
54        where
55            $( $x: FromToNativeWasmType, )*
56            Rets: WasmTypeList,
57        {
58            /// Call the typed func and return results.
59            #[allow(unused_mut)]
60            #[allow(clippy::too_many_arguments)]
61            pub fn call(&self, store: &mut impl AsStoreMut, $( $x: $x, )* ) -> Result<Rets, RuntimeError> where $( $x: FromToNativeWasmType, )*
62
63            {
64                $(
65                    let [<p_ $x>] = $x;
66                )*
67                match store.as_store_mut().inner.store {
68                    #[cfg(feature = "sys")]
69                    BackendStore::Sys(_) => self.call_sys(store, $([<p_ $x>]),*),
70                    #[cfg(feature = "wamr")]
71                    BackendStore::Wamr(_) => self.call_wamr(store, $([<p_ $x>]),*),
72                    #[cfg(feature = "wasmi")]
73                    BackendStore::Wasmi(_) => self.call_wasmi(store, $([<p_ $x>]),*),
74                    #[cfg(feature = "v8")]
75                    BackendStore::V8(_) => self.call_v8(store, $([<p_ $x>]),*),
76                    #[cfg(feature = "js")]
77                    BackendStore::Js(_) => self.call_js(store, $([<p_ $x>]),*),
78                    #[cfg(feature = "jsc")]
79                    BackendStore::Jsc(_) => self.call_jsc(store, $([<p_ $x>]),*),
80
81                }
82            }
83
84            /// Call the typed func asynchronously.
85            #[cfg(feature = "experimental-async")]
86            #[allow(unused_mut)]
87            #[allow(clippy::too_many_arguments)]
88            pub fn call_async(
89                &self,
90                store: &impl AsStoreAsync,
91                $( $x: $x, )*
92            ) -> impl Future<Output = Result<Rets, RuntimeError>> + Sized + 'static
93            where
94                $( $x: FromToNativeWasmType + 'static, )*
95            {
96                $(
97                    let [<p_ $x>] = $x;
98                )*
99                let store = store.store();
100                let func = self.func.clone();
101                async move {
102                    let read_lock = store.read_lock().await;
103                    match read_lock.as_store_ref().inner.store {
104                        #[cfg(feature = "sys")]
105                        BackendStore::Sys(_) => {
106                            drop(read_lock);
107                            Self::call_async_sys(func, store, $([<p_ $x>]),*).await
108                        }
109                        #[cfg(feature = "wamr")]
110                        BackendStore::Wamr(_) => async_backend_error(),
111                        #[cfg(feature = "wasmi")]
112                        BackendStore::Wasmi(_) => async_backend_error(),
113                        #[cfg(feature = "v8")]
114                        BackendStore::V8(_) => async_backend_error(),
115                        #[cfg(feature = "js")]
116                        BackendStore::Js(_) => async_backend_error(),
117                        #[cfg(feature = "jsc")]
118                        BackendStore::Jsc(_) => async_backend_error(),
119                    }
120                }
121            }
122
123            #[doc(hidden)]
124            #[allow(missing_docs)]
125            #[allow(unused_mut)]
126            #[allow(clippy::too_many_arguments)]
127            pub fn call_raw(&self, store: &mut impl AsStoreMut, mut params_list: Vec<RawValue> ) -> Result<Rets, RuntimeError> {
128                match store.as_store_mut().inner.store {
129                    #[cfg(feature = "sys")]
130                    BackendStore::Sys(_) => self.call_raw_sys(store, params_list),
131                    #[cfg(feature = "wamr")]
132                    BackendStore::Wamr(_) => self.call_raw_wamr(store, params_list),
133                    #[cfg(feature = "wasmi")]
134                    BackendStore::Wasmi(_) => self.call_raw_wasmi(store, params_list),
135                    #[cfg(feature = "v8")]
136                    BackendStore::V8(_) => self.call_raw_v8(store, params_list),
137                    #[cfg(feature = "js")]
138                    BackendStore::Js(_) => self.call_raw_js(store, params_list),
139                    #[cfg(feature = "jsc")]
140                    BackendStore::Jsc(_) => self.call_raw_jsc(store, params_list),
141                }
142            }
143        }
144        }
145    };
146}
147
148impl_native_traits!();
149impl_native_traits!(A1);
150impl_native_traits!(A1, A2);
151impl_native_traits!(A1, A2, A3);
152impl_native_traits!(A1, A2, A3, A4);
153impl_native_traits!(A1, A2, A3, A4, A5);
154impl_native_traits!(A1, A2, A3, A4, A5, A6);
155impl_native_traits!(A1, A2, A3, A4, A5, A6, A7);
156impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8);
157impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
158impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
159impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
160impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
161impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
162impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
163impl_native_traits!(
164    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15
165);
166impl_native_traits!(
167    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16
168);
169impl_native_traits!(
170    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17
171);
172impl_native_traits!(
173    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18
174);
175impl_native_traits!(
176    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19
177);
178impl_native_traits!(
179    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20
180);
181
182fn async_backend_error<Rets>() -> Result<Rets, RuntimeError> {
183    Err(RuntimeError::new(
184        "async calls are only supported with the `sys` backend",
185    ))
186}