#[cfg(feature = "js")]
use crate::js::externals::function as function_impl;
#[cfg(feature = "jsc")]
use crate::jsc::externals::function as function_impl;
#[cfg(feature = "sys")]
use crate::sys::externals::function as function_impl;
use crate::exports::{ExportError, Exportable};
use crate::store::{AsStoreMut, AsStoreRef};
use crate::vm::{VMExtern, VMExternFunction, VMFuncRef, VMFunctionCallback, VMTrampoline};
use crate::{
Extern, FunctionEnv, FunctionEnvMut, FunctionType, RuntimeError, TypedFunction, Value,
};
use wasmer_types::RawValue;
use crate::native_type::WasmTypeList;
pub trait HostFunction<T, Args, Rets, Kind>
where
Args: WasmTypeList,
Rets: WasmTypeList,
Kind: HostFunctionKind,
{
fn function_callback(&self) -> VMFunctionCallback;
fn call_trampoline_address() -> VMTrampoline {
unimplemented!();
}
}
#[doc(hidden)]
pub trait HostFunctionKind: private::HostFunctionKindSealed {}
pub struct WithEnv;
impl HostFunctionKind for WithEnv {}
pub struct WithoutEnv;
impl HostFunctionKind for WithoutEnv {}
mod private {
pub trait HostFunctionKindSealed {}
impl HostFunctionKindSealed for super::WithEnv {}
impl HostFunctionKindSealed for super::WithoutEnv {}
}
#[derive(Debug, Clone, PartialEq)]
pub struct Function(pub(crate) function_impl::Function);
impl Function {
pub fn new<FT, F>(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self
where
FT: Into<FunctionType>,
F: Fn(&[Value]) -> Result<Vec<Value>, RuntimeError> + 'static + Send + Sync,
{
let env = FunctionEnv::new(&mut store.as_store_mut(), ());
let wrapped_func = move |_env: FunctionEnvMut<()>,
args: &[Value]|
-> Result<Vec<Value>, RuntimeError> { func(args) };
Self::new_with_env(store, &env, ty, wrapped_func)
}
pub fn new_with_env<FT, F, T: Send + 'static>(
store: &mut impl AsStoreMut,
env: &FunctionEnv<T>,
ty: FT,
func: F,
) -> Self
where
FT: Into<FunctionType>,
F: Fn(FunctionEnvMut<T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
+ 'static
+ Send
+ Sync,
{
Self(function_impl::Function::new_with_env(store, env, ty, func))
}
pub fn new_typed<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
where
F: HostFunction<(), Args, Rets, WithoutEnv> + 'static + Send + Sync,
Args: WasmTypeList,
Rets: WasmTypeList,
{
Self(function_impl::Function::new_typed(store, func))
}
pub fn new_typed_with_env<T: Send + 'static, F, Args, Rets>(
store: &mut impl AsStoreMut,
env: &FunctionEnv<T>,
func: F,
) -> Self
where
F: HostFunction<T, Args, Rets, WithEnv> + 'static + Send + Sync,
Args: WasmTypeList,
Rets: WasmTypeList,
{
Self(function_impl::Function::new_typed_with_env(
store, env, func,
))
}
pub fn ty(&self, store: &impl AsStoreRef) -> FunctionType {
self.0.ty(store)
}
pub fn param_arity(&self, store: &impl AsStoreRef) -> usize {
self.ty(store).params().len()
}
pub fn result_arity(&self, store: &impl AsStoreRef) -> usize {
self.ty(store).results().len()
}
pub fn call(
&self,
store: &mut impl AsStoreMut,
params: &[Value],
) -> Result<Box<[Value]>, RuntimeError> {
self.0.call(store, params)
}
#[doc(hidden)]
#[allow(missing_docs)]
pub fn call_raw(
&self,
store: &mut impl AsStoreMut,
params: Vec<RawValue>,
) -> Result<Box<[Value]>, RuntimeError> {
self.0.call_raw(store, params)
}
pub(crate) fn vm_funcref(&self, store: &impl AsStoreRef) -> VMFuncRef {
self.0.vm_funcref(store)
}
pub(crate) unsafe fn from_vm_funcref(store: &mut impl AsStoreMut, funcref: VMFuncRef) -> Self {
Self(function_impl::Function::from_vm_funcref(store, funcref))
}
pub fn typed<Args, Rets>(
&self,
store: &impl AsStoreRef,
) -> Result<TypedFunction<Args, Rets>, RuntimeError>
where
Args: WasmTypeList,
Rets: WasmTypeList,
{
let ty = self.ty(store);
{
let expected = ty.params();
let given = Args::wasm_types();
if expected != given {
return Err(RuntimeError::new(format!(
"given types (`{:?}`) for the function arguments don't match the actual types (`{:?}`)",
given,
expected,
)));
}
}
{
let expected = ty.results();
let given = Rets::wasm_types();
if expected != given {
return Err(RuntimeError::new(format!(
"given types (`{:?}`) for the function results don't match the actual types (`{:?}`)",
given,
expected,
)));
}
}
Ok(TypedFunction::new(store, self.clone()))
}
pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self {
Self(function_impl::Function::from_vm_extern(store, vm_extern))
}
pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
self.0.is_from_store(store)
}
pub(crate) fn to_vm_extern(&self) -> VMExtern {
self.0.to_vm_extern()
}
}
impl std::cmp::Eq for Function {}
impl<'a> Exportable<'a> for Function {
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
match _extern {
Extern::Function(func) => Ok(func),
_ => Err(ExportError::IncompatibleType),
}
}
}