use std::sync::Arc;
use crate::engine::Engine;
use crate::func::wasm_ty::{WasmRet, WasmTy};
use crate::func::Caller;
use crate::store::HostFunc;
use crate::value::{FuncType, ValType};
#[cfg(feature = "async")]
use crate::func::wasm_ty::WasmResults;
#[cfg(feature = "async")]
use crate::store::AsyncHostFunc;
pub trait IntoFunc<T, Params, Results>: Send + Sync + 'static {
fn into_func(self, engine: &Engine) -> (FuncType, HostFunc<T>);
}
fn make_ty<R: WasmRet>(engine: &Engine, params: Vec<ValType>) -> FuncType {
let mut results = Vec::new();
R::valtypes(&mut results);
FuncType::new(engine, params, results)
}
#[cfg(feature = "async")]
pub(crate) fn into_async_func<T, F, P, R>(engine: &Engine, func: F) -> (FuncType, AsyncHostFunc<T>)
where
F: for<'a> Fn(
Caller<'a, T>,
P,
) -> std::boxed::Box<dyn std::future::Future<Output = R> + Send + 'a>
+ Send
+ Sync
+ 'static,
P: WasmResults,
R: WasmRet + 'static,
T: Send + 'static,
{
let mut params = Vec::new();
P::valtypes(&mut params);
let ty = make_ty::<R>(engine, params);
let cb: AsyncHostFunc<T> = Arc::new(move |caller, vals, results| {
let p = P::from_vals(vals);
let user_fut = func(caller, p);
std::boxed::Box::new(async move {
let r = std::boxed::Box::into_pin(user_fut).await;
r.into_results(results)
})
});
(ty, cb)
}
macro_rules! impl_into_func {
(0) => {
impl<T, F, R> IntoFunc<T, (), R> for F
where
F: Fn() -> R + Send + Sync + 'static,
R: WasmRet,
T: 'static,
{
fn into_func(self, engine: &Engine) -> (FuncType, HostFunc<T>) {
let ty = make_ty::<R>(engine, Vec::new());
let cb: HostFunc<T> = Arc::new(move |_caller, _params, results| {
self().into_results(results)
});
(ty, cb)
}
}
impl<T, F, R> IntoFunc<T, (Caller<'_, T>,), R> for F
where
F: Fn(Caller<'_, T>) -> R + Send + Sync + 'static,
R: WasmRet,
T: 'static,
{
fn into_func(self, engine: &Engine) -> (FuncType, HostFunc<T>) {
let ty = make_ty::<R>(engine, Vec::new());
let cb: HostFunc<T> = Arc::new(move |caller, _params, results| {
self(caller).into_results(results)
});
(ty, cb)
}
}
};
(1 $arg:ident) => {
impl<T, F, $arg, R> IntoFunc<T, $arg, R> for F
where
F: Fn($arg) -> R + Send + Sync + 'static,
$arg: WasmTy,
R: WasmRet,
T: 'static,
{
fn into_func(self, engine: &Engine) -> (FuncType, HostFunc<T>) {
let ty = make_ty::<R>(engine, vec![$arg::valtype()]);
let cb: HostFunc<T> = Arc::new(move |_caller, params, results| {
self($arg::from_val(params[0])).into_results(results)
});
(ty, cb)
}
}
impl<T, F, $arg, R> IntoFunc<T, (Caller<'_, T>, $arg), R> for F
where
F: Fn(Caller<'_, T>, $arg) -> R + Send + Sync + 'static,
$arg: WasmTy,
R: WasmRet,
T: 'static,
{
fn into_func(self, engine: &Engine) -> (FuncType, HostFunc<T>) {
let ty = make_ty::<R>(engine, vec![$arg::valtype()]);
let cb: HostFunc<T> = Arc::new(move |caller, params, results| {
self(caller, $arg::from_val(params[0])).into_results(results)
});
(ty, cb)
}
}
};
($n:tt $($args:ident)*) => {
impl<T, F, $($args,)* R> IntoFunc<T, ($($args,)*), R> for F
where
F: Fn($($args),*) -> R + Send + Sync + 'static,
$($args: WasmTy,)*
R: WasmRet,
T: 'static,
{
#[allow(non_snake_case)]
fn into_func(self, engine: &Engine) -> (FuncType, HostFunc<T>) {
let ty = make_ty::<R>(engine, vec![$($args::valtype()),*]);
let cb: HostFunc<T> = Arc::new(move |_caller, params, results| {
let mut it = params.iter().copied();
$(let $args = $args::from_val(it.next().expect("arity validated"));)*
self($($args),*).into_results(results)
});
(ty, cb)
}
}
impl<T, F, $($args,)* R> IntoFunc<T, (Caller<'_, T>, $($args,)*), R> for F
where
F: Fn(Caller<'_, T>, $($args),*) -> R + Send + Sync + 'static,
$($args: WasmTy,)*
R: WasmRet,
T: 'static,
{
#[allow(non_snake_case)]
fn into_func(self, engine: &Engine) -> (FuncType, HostFunc<T>) {
let ty = make_ty::<R>(engine, vec![$($args::valtype()),*]);
let cb: HostFunc<T> = Arc::new(move |caller, params, results| {
let mut it = params.iter().copied();
$(let $args = $args::from_val(it.next().expect("arity validated"));)*
self(caller, $($args),*).into_results(results)
});
(ty, cb)
}
}
};
}
crate::for_each_arity!(impl_into_func);