use std::marker::PhantomData;
use crate::sys::{
AsStoreMut, FromToNativeWasmType, Function, NativeWasmTypeInto, RuntimeError, WasmTypeList,
};
use wasmer_types::RawValue;
pub struct TypedFunction<Args, Rets> {
func: Function,
_phantom: PhantomData<fn(Args) -> Rets>,
}
unsafe impl<Args, Rets> Send for TypedFunction<Args, Rets> {}
impl<Args, Rets> TypedFunction<Args, Rets>
where
Args: WasmTypeList,
Rets: WasmTypeList,
{
pub(crate) fn new(func: Function) -> Self {
Self {
func,
_phantom: PhantomData,
}
}
}
impl<Args: WasmTypeList, Rets: WasmTypeList> Clone for TypedFunction<Args, Rets> {
fn clone(&self) -> Self {
Self {
func: self.func.clone(),
_phantom: PhantomData,
}
}
}
impl<Args, Rets> From<TypedFunction<Args, Rets>> for Function
where
Args: WasmTypeList,
Rets: WasmTypeList,
{
fn from(other: TypedFunction<Args, Rets>) -> Self {
other.func
}
}
macro_rules! impl_native_traits {
( $( $x:ident ),* ) => {
#[allow(unused_parens, non_snake_case)]
impl<$( $x , )* Rets> TypedFunction<( $( $x ),* ), Rets>
where
$( $x: FromToNativeWasmType, )*
Rets: WasmTypeList,
{
#[allow(unused_mut)]
#[allow(clippy::too_many_arguments)]
pub fn call(&self, store: &mut impl AsStoreMut, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
let anyfunc = unsafe {
*self.func
.handle
.get(store.as_store_ref().objects())
.anyfunc
.as_ptr()
.as_ref()
};
if $(!FromToNativeWasmType::is_from_store(&$x, store) ||)* false {
return Err(RuntimeError::new(
"cross-`Context` values are not supported",
));
}
let mut params_list = [ $( $x.to_native().into_raw(store) ),* ];
let mut rets_list_array = Rets::empty_array();
let rets_list: &mut [RawValue] = rets_list_array.as_mut();
let using_rets_array;
let args_rets: &mut [RawValue] = if params_list.len() > rets_list.len() {
using_rets_array = false;
params_list.as_mut()
} else {
using_rets_array = true;
for (i, &arg) in params_list.iter().enumerate() {
rets_list[i] = arg;
}
rets_list.as_mut()
};
unsafe {
wasmer_vm::wasmer_call_trampoline(
store.as_store_ref().signal_handler(),
anyfunc.vmctx,
anyfunc.call_trampoline,
anyfunc.func_ptr,
args_rets.as_mut_ptr() as *mut u8,
)
}?;
let num_rets = rets_list.len();
if !using_rets_array && num_rets > 0 {
let src_pointer = params_list.as_ptr();
let rets_list = &mut rets_list_array.as_mut()[0] as *mut RawValue;
unsafe {
std::ptr::copy_nonoverlapping(src_pointer,
rets_list,
num_rets);
}
}
Ok(unsafe { Rets::from_array(store, rets_list_array) })
}
}
};
}
impl_native_traits!();
impl_native_traits!(A1);
impl_native_traits!(A1, A2);
impl_native_traits!(A1, A2, A3);
impl_native_traits!(A1, A2, A3, A4);
impl_native_traits!(A1, A2, A3, A4, A5);
impl_native_traits!(A1, A2, A3, A4, A5, A6);
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7);
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8);
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15);
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16);
impl_native_traits!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17);
impl_native_traits!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18
);
impl_native_traits!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19
);
impl_native_traits!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20
);