Skip to main content

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 = "v8")]
71                    BackendStore::V8(_) => self.call_v8(store, $([<p_ $x>]),*),
72                    #[cfg(feature = "js")]
73                    BackendStore::Js(_) => self.call_js(store, $([<p_ $x>]),*),
74
75                }
76            }
77
78            /// Call the typed func asynchronously.
79            #[cfg(feature = "experimental-async")]
80            #[allow(unused_mut)]
81            #[allow(clippy::too_many_arguments)]
82            pub fn call_async(
83                &self,
84                store: &impl AsStoreAsync,
85                $( $x: $x, )*
86            ) -> impl Future<Output = Result<Rets, RuntimeError>> + Sized + 'static
87            where
88                $( $x: FromToNativeWasmType + 'static, )*
89            {
90                $(
91                    let [<p_ $x>] = $x;
92                )*
93                let store = store.store();
94                let func = self.func.clone();
95                async move {
96                    let read_lock = store.read_lock().await;
97                    match read_lock.as_store_ref().inner.store {
98                        #[cfg(feature = "sys")]
99                        BackendStore::Sys(_) => {
100                            drop(read_lock);
101                            Self::call_async_sys(func, store, $([<p_ $x>]),*).await
102                        }
103                        #[cfg(feature = "v8")]
104                        BackendStore::V8(_) => async_backend_error(),
105                        #[cfg(feature = "js")]
106                        BackendStore::Js(_) => {
107                            drop(read_lock);
108                            Self::call_async_js(func, store, $([<p_ $x>]),*).await
109                        }
110                    }
111                }
112            }
113
114            #[doc(hidden)]
115            #[allow(missing_docs)]
116            #[allow(unused_mut)]
117            #[allow(clippy::too_many_arguments)]
118            pub fn call_raw(&self, store: &mut impl AsStoreMut, mut params_list: Vec<RawValue> ) -> Result<Rets, RuntimeError> {
119                match store.as_store_mut().inner.store {
120                    #[cfg(feature = "sys")]
121                    BackendStore::Sys(_) => self.call_raw_sys(store, params_list),
122                    #[cfg(feature = "v8")]
123                    BackendStore::V8(_) => self.call_raw_v8(store, params_list),
124                    #[cfg(feature = "js")]
125                    BackendStore::Js(_) => self.call_raw_js(store, params_list),
126                }
127            }
128        }
129        }
130    };
131}
132
133impl_native_traits!();
134impl_native_traits!(A1);
135impl_native_traits!(A1, A2);
136impl_native_traits!(A1, A2, A3);
137impl_native_traits!(A1, A2, A3, A4);
138impl_native_traits!(A1, A2, A3, A4, A5);
139impl_native_traits!(A1, A2, A3, A4, A5, A6);
140impl_native_traits!(A1, A2, A3, A4, A5, A6, A7);
141impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8);
142impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
143impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
144impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
145impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
146impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
147impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
148impl_native_traits!(
149    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15
150);
151impl_native_traits!(
152    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16
153);
154impl_native_traits!(
155    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17
156);
157impl_native_traits!(
158    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18
159);
160impl_native_traits!(
161    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19
162);
163impl_native_traits!(
164    A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20
165);
166
167fn async_backend_error<Rets>() -> Result<Rets, RuntimeError> {
168    Err(RuntimeError::new(
169        "async calls are not supported with the `v8` backend",
170    ))
171}