use std::{future::Future, marker::PhantomData, pin::Pin};
use crate::{
AsyncFunctionEnvMut, HostFunctionKind, RuntimeError, WasmTypeList, WithEnv, WithoutEnv,
utils::{FromToNativeWasmType, IntoResult},
};
pub enum AsyncFunctionEnv<T, Kind> {
WithoutEnv(PhantomData<(T, Kind)>),
WithEnv(AsyncFunctionEnvMut<T>),
}
impl<T> AsyncFunctionEnv<T, WithoutEnv> {
pub fn new() -> Self {
Self::WithoutEnv(PhantomData)
}
}
impl<T> AsyncFunctionEnv<T, WithEnv> {
pub fn with_env(env: AsyncFunctionEnvMut<T>) -> Self {
Self::WithEnv(env)
}
pub fn into_env(self) -> AsyncFunctionEnvMut<T> {
match self {
Self::WithEnv(env) => env,
Self::WithoutEnv(_) => unreachable!("with-env async function called without env"),
}
}
}
pub trait AsyncHostFunction<T, Args, Rets, Kind>
where
Args: WasmTypeList + 'static,
Rets: WasmTypeList,
Kind: HostFunctionKind,
{
fn call_async(
&self,
env: AsyncFunctionEnv<T, Kind>,
args: Args,
) -> Pin<Box<dyn Future<Output = Result<Rets, RuntimeError>>>>;
}
macro_rules! impl_async_host_function_without_env {
( $( $x:ident ),* ) => {
impl<$( $x, )* Rets, RetsAsResult, F, Fut > AsyncHostFunction<(), ( $( $x ),* ), Rets, WithoutEnv> for F
where
F: Fn($( $x ),*) -> Fut + 'static,
Fut: Future<Output = RetsAsResult> + 'static,
RetsAsResult: IntoResult<Rets>,
Rets: WasmTypeList,
( $( $x ),* ): WasmTypeList + 'static,
$( $x: FromToNativeWasmType + 'static, )*
{
fn call_async(
&self,
_env: AsyncFunctionEnv<(), WithoutEnv>,
args: ( $( $x ),* ),
) -> Pin<Box<dyn Future<Output = Result<Rets, RuntimeError>>>> {
#[allow(non_snake_case)]
let ( $( $x ),* ) = args;
let fut = (self)( $( $x ),* );
Box::pin(async move {
fut.await
.into_result()
.map_err(|err| RuntimeError::from_dyn(Box::new(err)))
})
}
}
};
}
macro_rules! impl_async_host_function_with_env {
( $( $x:ident ),* ) => {
impl<$( $x, )* Rets, RetsAsResult, T, F, Fut > AsyncHostFunction<T, ( $( $x ),* ), Rets, WithEnv> for F
where
T: 'static,
F: Fn(AsyncFunctionEnvMut<T>, $( $x ),*) -> Fut + 'static,
Fut: Future<Output = RetsAsResult> + 'static,
RetsAsResult: IntoResult<Rets>,
Rets: WasmTypeList,
( $( $x ),* ): WasmTypeList + 'static,
$( $x: FromToNativeWasmType + 'static, )*
{
fn call_async(
&self,
env: AsyncFunctionEnv<T, WithEnv>,
args: ( $( $x ),* ),
) -> Pin<Box<dyn Future<Output = Result<Rets, RuntimeError>>>> {
#[allow(non_snake_case)]
let ( $( $x ),* ) = args;
let fut = (self)(env.into_env(), $( $x ),* );
Box::pin(async move {
fut.await
.into_result()
.map_err(|err| RuntimeError::from_dyn(Box::new(err)))
})
}
}
};
}
impl_async_host_function_without_env!();
impl_async_host_function_without_env!(A1);
impl_async_host_function_without_env!(A1, A2);
impl_async_host_function_without_env!(A1, A2, A3);
impl_async_host_function_without_env!(A1, A2, A3, A4);
impl_async_host_function_without_env!(A1, A2, A3, A4, A5);
impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6);
impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7);
impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8);
impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
impl_async_host_function_without_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
impl_async_host_function_without_env!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15
);
impl_async_host_function_without_env!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16
);
impl_async_host_function_without_env!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17
);
impl_async_host_function_without_env!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18
);
impl_async_host_function_without_env!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19
);
impl_async_host_function_without_env!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20
);
impl_async_host_function_with_env!();
impl_async_host_function_with_env!(A1);
impl_async_host_function_with_env!(A1, A2);
impl_async_host_function_with_env!(A1, A2, A3);
impl_async_host_function_with_env!(A1, A2, A3, A4);
impl_async_host_function_with_env!(A1, A2, A3, A4, A5);
impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6);
impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7);
impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8);
impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9);
impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10);
impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11);
impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12);
impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13);
impl_async_host_function_with_env!(A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14);
impl_async_host_function_with_env!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15
);
impl_async_host_function_with_env!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16
);
impl_async_host_function_with_env!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17
);
impl_async_host_function_with_env!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18
);
impl_async_host_function_with_env!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19
);
impl_async_host_function_with_env!(
A1, A2, A3, A4, A5, A6, A7, A8, A9, A10, A11, A12, A13, A14, A15, A16, A17, A18, A19, A20
);