pub(crate) mod inner;
pub use inner::*;
pub(crate) mod host;
pub use host::*;
pub(crate) mod env;
pub use env::*;
#[cfg(feature = "experimental-async")]
pub(crate) mod async_host;
#[cfg(feature = "experimental-async")]
pub use async_host::{AsyncFunctionEnv, AsyncHostFunction};
use std::{future::Future, pin::Pin};
use wasmer_types::{FunctionType, RawValue};
#[cfg(feature = "experimental-async")]
use crate::AsStoreAsync;
use crate::{
AsStoreMut, AsStoreRef, ExportError, Exportable, Extern, StoreMut, StoreRef, TypedFunction,
Value, WasmTypeList,
error::RuntimeError,
vm::{VMExtern, VMExternFunction, VMFuncRef},
};
#[derive(Debug, Clone, PartialEq, Eq)]
#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
pub struct Function(pub(crate) BackendFunction);
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,
{
Self(BackendFunction::new(store, ty, 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(BackendFunction::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(BackendFunction::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(BackendFunction::new_typed_with_env(store, env, func))
}
#[cfg(feature = "experimental-async")]
pub fn new_async<FT, F, Fut>(store: &mut impl AsStoreMut, ty: FT, func: F) -> Self
where
FT: Into<FunctionType>,
F: Fn(&[Value]) -> Fut + 'static,
Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,
{
Self(BackendFunction::new_async(store, ty, func))
}
#[cfg(feature = "experimental-async")]
pub fn new_with_env_async<FT, F, Fut, T: 'static>(
store: &mut impl AsStoreMut,
env: &FunctionEnv<T>,
ty: FT,
func: F,
) -> Self
where
FT: Into<FunctionType>,
F: Fn(AsyncFunctionEnvMut<T>, &[Value]) -> Fut + 'static,
Fut: Future<Output = Result<Vec<Value>, RuntimeError>> + 'static,
{
Self(BackendFunction::new_with_env_async(store, env, ty, func))
}
#[cfg(feature = "experimental-async")]
pub fn new_typed_async<F, Args, Rets>(store: &mut impl AsStoreMut, func: F) -> Self
where
Rets: WasmTypeList + 'static,
Args: WasmTypeList + 'static,
F: AsyncHostFunction<(), Args, Rets, WithoutEnv> + 'static,
{
Self(BackendFunction::new_typed_async(store, func))
}
#[cfg(feature = "experimental-async")]
pub fn new_typed_with_env_async<T: 'static, F, Args, Rets>(
store: &mut impl AsStoreMut,
env: &FunctionEnv<T>,
func: F,
) -> Self
where
Rets: WasmTypeList + 'static,
Args: WasmTypeList + 'static,
F: AsyncHostFunction<T, Args, Rets, WithEnv> + 'static,
{
Self(BackendFunction::new_typed_with_env_async(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)
}
#[must_use = "This function spawns a future that must be awaited to produce results"]
#[cfg(feature = "experimental-async")]
pub fn call_async(
&self,
store: &impl AsStoreAsync,
params: Vec<Value>,
) -> impl Future<Output = Result<Box<[Value]>, RuntimeError>> + 'static {
self.0.call_async(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 {
unsafe { Self(BackendFunction::from_vm_funcref(store, funcref)) }
}
pub fn typed<Args, Rets>(
&self,
store: &impl AsStoreRef,
) -> Result<TypedFunction<Args, Rets>, RuntimeError>
where
Args: WasmTypeList,
Rets: WasmTypeList,
{
self.0.typed(store)
}
pub(crate) fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExternFunction) -> Self {
Self(BackendFunction::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<'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),
}
}
}