use crate::AsContextMut;
use crate::FuncSig;
use crate::impl_for_each_function_signature;
use crate::RuntimeResult;
use crate::WasmBackend;
use crate::WValue;
pub trait HostFunction<WB: WasmBackend>: Send + Sync + Clone {
fn new<F>(store: &mut impl AsContextMut<WB>, sig: FuncSig, func: F) -> Self
where
F: for<'c> Fn(&[WValue]) -> anyhow::Result<Vec<WValue>> + Sync + Send + 'static;
fn new_with_caller<F>(store: &mut impl AsContextMut<WB>, sig: FuncSig, func: F) -> Self
where
F: for<'c> Fn(
<WB as WasmBackend>::ImportCallContext<'c>,
&[WValue],
) -> anyhow::Result<Vec<WValue>>
+ Sync
+ Send
+ 'static;
fn new_typed<Params, Results, Env>(
store: &mut impl AsContextMut<WB>,
func: impl IntoFunc<WB, Params, Results, Env>,
) -> Self;
fn signature(&self, store: &mut impl AsContextMut<WB>) -> FuncSig;
}
pub trait ExportFunction<WB: WasmBackend>: Send + Sync + Clone {
fn signature(&self, store: &mut impl AsContextMut<WB>) -> FuncSig;
fn call(
&self,
store: &mut impl AsContextMut<WB>,
args: &[WValue],
) -> RuntimeResult<Vec<WValue>>;
}
pub trait IntoFunc<WB: WasmBackend, Params, Results, Env> {
fn into_func(self, ctx: &mut impl AsContextMut<WB>) -> <WB as WasmBackend>::HostFunction;
}
pub struct WithEnv {}
pub struct WithoutEnv {}
#[macro_export]
macro_rules! replace_with {
($from:ident -> $to:ident) => {
$to
};
}
macro_rules! impl_into_func {
($num:tt $($args:ident)*) => (paste::paste!{
#[allow(non_snake_case)]
impl<WB, F> IntoFunc<WB, ($(replace_with!($args -> i32),)*), (), WithoutEnv> for F
where
WB: WasmBackend,
F: Fn($(replace_with!($args -> i32),)*) + Send + Sync + 'static,
{
fn into_func(self, ctx: &mut impl AsContextMut<WB>) -> <WB as WasmBackend>::HostFunction {
<WB as WasmBackend>::HostFunction:: [< new_typed_ $num >] (ctx.as_context_mut(), self)
}
}
#[allow(non_snake_case)]
impl<WB, F> IntoFunc<WB, ($(replace_with!($args -> i32),)*), (), WithEnv> for F
where
WB: WasmBackend,
F: Fn(<WB as WasmBackend>::ImportCallContext<'_>, $(replace_with!($args -> i32),)*) + Send + Sync + 'static,
{
fn into_func(self, ctx: &mut impl AsContextMut<WB>) -> <WB as WasmBackend>::HostFunction {
<WB as WasmBackend>::HostFunction:: [< new_typed_with_env_ $num >] (ctx.as_context_mut(), self)
}
}
#[allow(non_snake_case)]
impl<WB, F> IntoFunc<WB, ($(replace_with!($args -> i32),)*), i32, WithoutEnv> for F
where
WB: WasmBackend,
F: Fn($(replace_with!($args -> i32),)*) -> i32 + Send + Sync + 'static,
{
fn into_func(self, ctx: &mut impl AsContextMut<WB>) -> <WB as WasmBackend>::HostFunction {
<WB as WasmBackend>::HostFunction:: [< new_typed_ $num _r >] (ctx.as_context_mut(), self)
}
}
#[allow(non_snake_case)]
impl<WB, F> IntoFunc<WB, ($(replace_with!($args -> i32),)*), i32, WithEnv> for F
where
WB: WasmBackend,
F: Fn(<WB as WasmBackend>::ImportCallContext<'_>, $(replace_with!($args -> i32),)*) -> i32 + Send + Sync + 'static,
{
fn into_func(self, ctx: &mut impl AsContextMut<WB>) -> <WB as WasmBackend>::HostFunction {
<WB as WasmBackend>::HostFunction:: [< new_typed_with_env_ $num _r >] (ctx.as_context_mut(), self)
}
}
});
}
impl_for_each_function_signature!(impl_into_func);
macro_rules! declare_func_construction {
($num:tt $($args:ident)*) => (paste::paste!{
#[allow(non_snake_case)]
fn [< new_typed_ $num >]<F>(ctx: <WB as WasmBackend>::ContextMut<'_>, func: F) -> <WB as WasmBackend>::HostFunction
where F: Fn($(replace_with!($args -> i32),)*) + Send + Sync + 'static
{
let func = move |_: <WB as WasmBackend>::ImportCallContext<'_>, $($args,)*| { func($($args,)*)};
Self:: [< new_typed_with_env_ $num >] (ctx, func)
}
#[allow(non_snake_case)]
fn [< new_typed_with_env_ $num >]<F>(ctx: <WB as WasmBackend>::ContextMut<'_>, func: F) -> <WB as WasmBackend>::HostFunction
where F: Fn(<WB as WasmBackend>::ImportCallContext<'_>, $(replace_with!($args -> i32),)*) + Send + Sync + 'static;
#[allow(non_snake_case)]
fn [< new_typed_ $num _r>]<F>(ctx: <WB as WasmBackend>::ContextMut<'_>, func: F) -> <WB as WasmBackend>::HostFunction
where F: Fn($(replace_with!($args -> i32),)*) -> i32 + Send + Sync + 'static
{
let func = move |_: <WB as WasmBackend>::ImportCallContext<'_>, $($args,)*| -> i32 { func($($args,)*)};
Self:: [< new_typed_with_env_ $num _r >] (ctx, func)
}
#[allow(non_snake_case)]
fn [< new_typed_with_env_ $num _r>]<F>(ctx: <WB as WasmBackend>::ContextMut<'_>, func: F) -> <WB as WasmBackend>::HostFunction
where F: Fn(<WB as WasmBackend>::ImportCallContext<'_>, $(replace_with!($args -> i32),)*) -> i32 + Send + Sync + 'static;
});
}
pub trait FuncConstructor<WB: WasmBackend> {
impl_for_each_function_signature!(declare_func_construction);
}