use super::{into_func::WasmTyList, Func};
use crate::{
core::UntypedVal,
engine::{CallParams, CallResults},
AsContext,
AsContextMut,
Error,
TypedResumableCall,
};
use core::{fmt, fmt::Debug, marker::PhantomData};
#[repr(transparent)]
pub struct TypedFunc<Params, Results> {
signature: PhantomData<fn(Params) -> Results>,
func: Func,
}
impl<Params, Results> Debug for TypedFunc<Params, Results> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("TypedFunc")
.field("signature", &self.signature)
.field("func", &self.func)
.finish()
}
}
impl<Params, Results> Copy for TypedFunc<Params, Results> {}
impl<Params, Results> Clone for TypedFunc<Params, Results> {
fn clone(&self) -> TypedFunc<Params, Results> {
*self
}
}
impl<Params, Results> TypedFunc<Params, Results> {
pub fn func(&self) -> &Func {
&self.func
}
}
impl<Params, Results> TypedFunc<Params, Results>
where
Params: WasmParams,
Results: WasmResults,
{
pub(crate) fn new(ctx: impl AsContext, func: Func) -> Result<Self, Error> {
let func_type = func.ty(&ctx);
let (actual_params, actual_results) = (
<Params as WasmTyList>::types(),
<Results as WasmTyList>::types(),
);
func_type.match_params(actual_params.as_ref())?;
func_type.match_results(actual_results.as_ref())?;
Ok(Self {
signature: PhantomData,
func,
})
}
pub fn call(&self, mut ctx: impl AsContextMut, params: Params) -> Result<Results, Error> {
ctx.as_context().store.engine().clone().execute_func(
ctx.as_context_mut(),
&self.func,
params,
<CallResultsTuple<Results>>::default(),
)
}
pub fn call_resumable(
&self,
mut ctx: impl AsContextMut,
params: Params,
) -> Result<TypedResumableCall<Results>, Error> {
ctx.as_context()
.store
.engine()
.clone()
.execute_func_resumable(
ctx.as_context_mut(),
&self.func,
params,
<CallResultsTuple<Results>>::default(),
)
.map(TypedResumableCall::new)
}
}
impl<Params> CallParams for Params
where
Params: WasmParams,
{
type Params = <Params as WasmTyList>::ValuesIter;
#[inline]
fn call_params(self) -> Self::Params {
<Params as WasmTyList>::values(self).into_iter()
}
}
pub struct CallResultsTuple<Results> {
_marker: PhantomData<fn() -> Results>,
}
impl<Results> Default for CallResultsTuple<Results> {
fn default() -> Self {
Self {
_marker: PhantomData,
}
}
}
impl<Results> Copy for CallResultsTuple<Results> {}
impl<Results> Clone for CallResultsTuple<Results> {
fn clone(&self) -> Self {
*self
}
}
impl<Results> CallResults for CallResultsTuple<Results>
where
Results: WasmResults,
{
type Results = Results;
fn len_results(&self) -> usize {
<Results as WasmTyList>::LEN
}
fn call_results(self, results: &[UntypedVal]) -> Self::Results {
<Results as WasmTyList>::from_values(results)
.expect("unable to construct typed results from call results")
}
}
pub trait WasmParams: WasmTyList {}
impl<T> WasmParams for T where T: WasmTyList {}
pub trait WasmResults: WasmTyList {}
impl<T> WasmResults for T where T: WasmTyList {}