mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-21 20:51:32 +00:00
Add typed functions and weird type parameter things
This commit is contained in:
@ -3,12 +3,12 @@ use crate::types::{
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub type Result<T> = std::result::Result<T, Box<Error>>;
|
||||
pub type CompileResult<T> = std::result::Result<T, Box<CompileError>>;
|
||||
pub type Result<T> = std::result::Result<T, Error>;
|
||||
pub type CompileResult<T> = std::result::Result<T, CompileError>;
|
||||
pub type LinkResult<T> = std::result::Result<T, Vec<LinkError>>;
|
||||
pub type RuntimeResult<T> = std::result::Result<T, Box<RuntimeError>>;
|
||||
pub type CallResult<T> = std::result::Result<T, Box<CallError>>;
|
||||
pub type ResolveResult<T> = std::result::Result<T, Box<ResolveError>>;
|
||||
pub type RuntimeResult<T> = std::result::Result<T, RuntimeError>;
|
||||
pub type CallResult<T> = std::result::Result<T, CallError>;
|
||||
pub type ResolveResult<T> = std::result::Result<T, ResolveError>;
|
||||
|
||||
/// This is returned when the chosen compiler is unable to
|
||||
/// successfully compile the provided webassembly module into
|
||||
@ -175,80 +175,44 @@ impl PartialEq for Error {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<CompileError>> for Box<Error> {
|
||||
fn from(compile_err: Box<CompileError>) -> Self {
|
||||
Box::new(Error::CompileError(*compile_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<LinkError>> for Box<Error> {
|
||||
fn from(link_err: Vec<LinkError>) -> Self {
|
||||
Box::new(Error::LinkError(link_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<RuntimeError>> for Box<Error> {
|
||||
fn from(runtime_err: Box<RuntimeError>) -> Self {
|
||||
Box::new(Error::RuntimeError(*runtime_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<ResolveError>> for Box<Error> {
|
||||
fn from(resolve_err: Box<ResolveError>) -> Self {
|
||||
Box::new(Error::ResolveError(*resolve_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<CallError>> for Box<Error> {
|
||||
fn from(call_err: Box<CallError>) -> Self {
|
||||
Box::new(Error::CallError(*call_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<RuntimeError>> for Box<CallError> {
|
||||
fn from(runtime_err: Box<RuntimeError>) -> Self {
|
||||
Box::new(CallError::Runtime(*runtime_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Box<ResolveError>> for Box<CallError> {
|
||||
fn from(resolve_err: Box<ResolveError>) -> Self {
|
||||
Box::new(CallError::Resolve(*resolve_err))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CompileError> for Box<Error> {
|
||||
impl From<CompileError> for Error {
|
||||
fn from(compile_err: CompileError) -> Self {
|
||||
Box::new(Error::CompileError(compile_err))
|
||||
Error::CompileError(compile_err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RuntimeError> for Box<Error> {
|
||||
impl From<RuntimeError> for Error {
|
||||
fn from(runtime_err: RuntimeError) -> Self {
|
||||
Box::new(Error::RuntimeError(runtime_err))
|
||||
Error::RuntimeError(runtime_err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CallError> for Box<Error> {
|
||||
impl From<CallError> for Error {
|
||||
fn from(call_err: CallError) -> Self {
|
||||
Box::new(Error::CallError(call_err))
|
||||
Error::CallError(call_err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CreationError> for Box<Error> {
|
||||
impl From<CreationError> for Error {
|
||||
fn from(creation_err: CreationError) -> Self {
|
||||
Box::new(Error::CreationError(creation_err))
|
||||
Error::CreationError(creation_err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RuntimeError> for Box<CallError> {
|
||||
impl From<Vec<LinkError>> for Error {
|
||||
fn from(link_errs: Vec<LinkError>) -> Self {
|
||||
Error::LinkError(link_errs)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RuntimeError> for CallError {
|
||||
fn from(runtime_err: RuntimeError) -> Self {
|
||||
Box::new(CallError::Runtime(runtime_err))
|
||||
CallError::Runtime(runtime_err)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<ResolveError> for Box<CallError> {
|
||||
impl From<ResolveError> for CallError {
|
||||
fn from(resolve_err: ResolveError) -> Self {
|
||||
Box::new(CallError::Resolve(resolve_err))
|
||||
CallError::Resolve(resolve_err)
|
||||
}
|
||||
}
|
||||
|
@ -28,11 +28,11 @@ impl IsExport for Export {
|
||||
/// # use wasmer_runtime_core::vm::Ctx;
|
||||
/// let import_object = imports! {
|
||||
/// "env" => {
|
||||
/// "foo" => func!(foo, [i32] -> [i32]),
|
||||
/// "foo" => func!(foo),
|
||||
/// },
|
||||
/// };
|
||||
///
|
||||
/// extern fn foo(n: i32, _: &mut Ctx) -> i32 {
|
||||
/// fn foo(n: i32, _: &mut Ctx) -> i32 {
|
||||
/// n
|
||||
/// }
|
||||
/// ```
|
||||
|
@ -8,6 +8,7 @@ use crate::{
|
||||
memory::Memory,
|
||||
module::{ExportIndex, Module, ModuleInner},
|
||||
table::Table,
|
||||
typed_func::{Func, Safe, WasmTypeList},
|
||||
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Value},
|
||||
vm,
|
||||
};
|
||||
@ -80,21 +81,30 @@ impl Instance {
|
||||
Ok(instance)
|
||||
}
|
||||
|
||||
/// This returns the representation of a function that can be called
|
||||
/// safely.
|
||||
/// Through generic magic and the awe-inspiring power of traits, we bring you...
|
||||
///
|
||||
/// # "Func"
|
||||
///
|
||||
/// A [`Func`] allows you to call functions exported from wasm with
|
||||
/// near zero overhead.
|
||||
///
|
||||
/// [`Func`]: struct.Func.html
|
||||
/// # Usage:
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer_runtime_core::Instance;
|
||||
/// # use wasmer_runtime_core::error::CallResult;
|
||||
/// # fn call_foo(instance: &mut Instance) -> CallResult<()> {
|
||||
/// instance
|
||||
/// .func("foo")?
|
||||
/// .call(&[])?;
|
||||
/// # use wasmer_runtime_core::{Func, Instance, error::ResolveResult};
|
||||
/// # fn typed_func(instance: Instance) -> ResolveResult<()> {
|
||||
/// let func: Func<(i32, i32)> = instance.func("foo")?;
|
||||
///
|
||||
/// func.call(42, 43);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn func(&self, name: &str) -> ResolveResult<Function> {
|
||||
pub fn func<Args, Rets>(&self, name: &str) -> ResolveResult<Func<Args, Rets, Safe>>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
let export_index =
|
||||
self.module
|
||||
.exports
|
||||
@ -111,7 +121,76 @@ impl Instance {
|
||||
.expect("broken invariant, incorrect func index");
|
||||
let signature = self.module.sig_registry.lookup_signature(sig_index);
|
||||
|
||||
Ok(Function {
|
||||
if signature.params() != Args::types() || signature.returns() != Rets::types() {
|
||||
Err(ResolveError::Signature {
|
||||
expected: Arc::clone(&signature),
|
||||
found: Args::types().to_vec(),
|
||||
})?;
|
||||
}
|
||||
|
||||
let ctx = match func_index.local_or_import(&*self.module) {
|
||||
LocalOrImport::Local(_) => self.inner.vmctx,
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
self.inner.import_backing.vm_functions[imported_func_index].vmctx
|
||||
}
|
||||
};
|
||||
|
||||
let func_ptr = match func_index.local_or_import(&self.module) {
|
||||
LocalOrImport::Local(local_func_index) => self
|
||||
.module
|
||||
.func_resolver
|
||||
.get(&self.module, local_func_index)
|
||||
.unwrap()
|
||||
.as_ptr(),
|
||||
LocalOrImport::Import(import_func_index) => {
|
||||
self.inner.import_backing.vm_functions[import_func_index].func
|
||||
}
|
||||
};
|
||||
|
||||
let typed_func: Func<Args, Rets, Safe> =
|
||||
unsafe { Func::new_from_ptr(func_ptr as _, ctx) };
|
||||
|
||||
Ok(typed_func)
|
||||
} else {
|
||||
Err(ResolveError::ExportWrongType {
|
||||
name: name.to_string(),
|
||||
}
|
||||
.into())
|
||||
}
|
||||
}
|
||||
|
||||
/// This returns the representation of a function that can be called
|
||||
/// safely.
|
||||
///
|
||||
/// # Usage:
|
||||
/// ```
|
||||
/// # use wasmer_runtime_core::Instance;
|
||||
/// # use wasmer_runtime_core::error::CallResult;
|
||||
/// # fn call_foo(instance: &mut Instance) -> CallResult<()> {
|
||||
/// instance
|
||||
/// .dyn_func("foo")?
|
||||
/// .call(&[])?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn dyn_func(&self, name: &str) -> ResolveResult<DynFunc> {
|
||||
let export_index =
|
||||
self.module
|
||||
.exports
|
||||
.get(name)
|
||||
.ok_or_else(|| ResolveError::ExportNotFound {
|
||||
name: name.to_string(),
|
||||
})?;
|
||||
|
||||
if let ExportIndex::Func(func_index) = export_index {
|
||||
let sig_index = *self
|
||||
.module
|
||||
.func_assoc
|
||||
.get(*func_index)
|
||||
.expect("broken invariant, incorrect func index");
|
||||
let signature = self.module.sig_registry.lookup_signature(sig_index);
|
||||
|
||||
Ok(DynFunc {
|
||||
signature,
|
||||
module: &self.module,
|
||||
instance_inner: &self.inner,
|
||||
@ -343,14 +422,14 @@ impl LikeNamespace for Instance {
|
||||
}
|
||||
|
||||
/// A representation of an exported WebAssembly function.
|
||||
pub struct Function<'a> {
|
||||
pub struct DynFunc<'a> {
|
||||
pub(crate) signature: Arc<FuncSig>,
|
||||
module: &'a ModuleInner,
|
||||
pub(crate) instance_inner: &'a InstanceInner,
|
||||
func_index: FuncIndex,
|
||||
}
|
||||
|
||||
impl<'a> Function<'a> {
|
||||
impl<'a> DynFunc<'a> {
|
||||
/// Call an exported webassembly function safely.
|
||||
///
|
||||
/// Pass arguments by wrapping each one in the [`Value`] enum.
|
||||
|
@ -18,6 +18,7 @@ mod sig_registry;
|
||||
pub mod structures;
|
||||
mod sys;
|
||||
pub mod table;
|
||||
mod typed_func;
|
||||
pub mod types;
|
||||
pub mod units;
|
||||
pub mod vm;
|
||||
@ -31,6 +32,8 @@ pub use self::error::Result;
|
||||
pub use self::instance::Instance;
|
||||
#[doc(inline)]
|
||||
pub use self::module::Module;
|
||||
#[doc(inline)]
|
||||
pub use self::typed_func::Func;
|
||||
use std::sync::Arc;
|
||||
|
||||
pub mod prelude {
|
||||
|
@ -14,21 +14,8 @@ macro_rules! debug {
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! func {
|
||||
($func:path, [ $( $params:ident ),* ] -> [ $( $returns:ident ),* ] ) => {{
|
||||
use $crate::{
|
||||
export::{Context, Export, FuncPointer},
|
||||
types::{FuncSig, Type, WasmExternType},
|
||||
vm,
|
||||
};
|
||||
let func: extern fn( $( $params, )* &mut vm::Ctx) -> ($( $returns )*) = $func;
|
||||
Export::Function {
|
||||
func: unsafe { FuncPointer::new(func as _) },
|
||||
ctx: Context::Internal,
|
||||
signature: FuncSig::new(
|
||||
&[ $( <$params as WasmExternType>::TYPE, )* ] as &[Type],
|
||||
&[ $( <$returns as WasmExternType>::TYPE, )* ] as &[Type],
|
||||
).into(),
|
||||
}
|
||||
($func:path) => {{
|
||||
$crate::Func::new($func)
|
||||
}};
|
||||
}
|
||||
|
||||
@ -47,11 +34,11 @@ macro_rules! func {
|
||||
/// # use wasmer_runtime_core::vm::Ctx;
|
||||
/// let import_object = imports! {
|
||||
/// "env" => {
|
||||
/// "foo" => func!(foo, [i32] -> [i32]),
|
||||
/// "foo" => func!(foo),
|
||||
/// },
|
||||
/// };
|
||||
///
|
||||
/// extern fn foo(n: i32, _: &mut Ctx) -> i32 {
|
||||
/// fn foo(n: i32, _: &mut Ctx) -> i32 {
|
||||
/// n
|
||||
/// }
|
||||
/// ```
|
||||
|
@ -1,6 +1,6 @@
|
||||
use crate::{
|
||||
error::CreationError,
|
||||
instance::Function,
|
||||
instance::DynFunc,
|
||||
sig_registry::SigRegistry,
|
||||
structures::TypedIndex,
|
||||
types::{FuncSig, TableDescriptor},
|
||||
@ -14,7 +14,7 @@ enum AnyfuncInner<'a> {
|
||||
ptr: *const vm::Func,
|
||||
signature: Arc<FuncSig>,
|
||||
},
|
||||
Managed(Function<'a>),
|
||||
Managed(DynFunc<'a>),
|
||||
}
|
||||
|
||||
pub struct Anyfunc<'a> {
|
||||
@ -35,8 +35,8 @@ impl<'a> Anyfunc<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Function<'a>> for Anyfunc<'a> {
|
||||
fn from(function: Function<'a>) -> Self {
|
||||
impl<'a> From<DynFunc<'a>> for Anyfunc<'a> {
|
||||
fn from(function: DynFunc<'a>) -> Self {
|
||||
Anyfunc {
|
||||
inner: AnyfuncInner::Managed(function),
|
||||
}
|
||||
|
232
lib/runtime-core/src/typed_func.rs
Normal file
232
lib/runtime-core/src/typed_func.rs
Normal file
@ -0,0 +1,232 @@
|
||||
use crate::{
|
||||
error::RuntimeError,
|
||||
export::{Context, Export, FuncPointer},
|
||||
import::IsExport,
|
||||
types::{FuncSig, Type, WasmExternType},
|
||||
vm::Ctx,
|
||||
};
|
||||
use std::{marker::PhantomData, mem, ptr, sync::Arc};
|
||||
|
||||
pub trait Safeness {}
|
||||
pub struct Safe;
|
||||
pub struct Unsafe;
|
||||
impl Safeness for Safe {}
|
||||
impl Safeness for Unsafe {}
|
||||
|
||||
pub trait WasmTypeList {
|
||||
type CStruct;
|
||||
fn from_c_struct(c_struct: Self::CStruct) -> Self;
|
||||
fn into_c_struct(self) -> Self::CStruct;
|
||||
fn types() -> &'static [Type];
|
||||
unsafe fn call<Rets>(self, f: *const (), ctx: *mut Ctx) -> Rets
|
||||
where
|
||||
Rets: WasmTypeList;
|
||||
}
|
||||
|
||||
pub trait ExternalFunction<Args, Rets>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
fn to_raw(self) -> *const ();
|
||||
}
|
||||
|
||||
pub struct Func<'a, Args = (), Rets = (), Safety: Safeness = Safe> {
|
||||
f: *const (),
|
||||
ctx: *mut Ctx,
|
||||
_phantom: PhantomData<(&'a (), Safety, Args, Rets)>,
|
||||
}
|
||||
|
||||
impl<'a, Args, Rets> Func<'a, Args, Rets, Safe>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
pub(crate) unsafe fn new_from_ptr(f: *const (), ctx: *mut Ctx) -> Func<'a, Args, Rets, Safe> {
|
||||
Func {
|
||||
f,
|
||||
ctx,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Args, Rets> Func<'a, Args, Rets, Unsafe>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
pub fn new<F>(f: F) -> Func<'a, Args, Rets, Unsafe>
|
||||
where
|
||||
F: ExternalFunction<Args, Rets>,
|
||||
{
|
||||
Func {
|
||||
f: f.to_raw(),
|
||||
ctx: ptr::null_mut(),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, Args, Rets, Safety> Func<'a, Args, Rets, Safety>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
Safety: Safeness,
|
||||
{
|
||||
pub fn params(&self) -> &'static [Type] {
|
||||
Args::types()
|
||||
}
|
||||
pub fn returns(&self) -> &'static [Type] {
|
||||
Rets::types()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A: WasmExternType> WasmTypeList for (A,) {
|
||||
type CStruct = S1<A>;
|
||||
fn from_c_struct(c_struct: Self::CStruct) -> Self {
|
||||
let S1(a) = c_struct;
|
||||
(a,)
|
||||
}
|
||||
fn into_c_struct(self) -> Self::CStruct {
|
||||
#[allow(unused_parens, non_snake_case)]
|
||||
let (a,) = self;
|
||||
S1(a)
|
||||
}
|
||||
fn types() -> &'static [Type] {
|
||||
&[A::TYPE]
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn call<Rets: WasmTypeList>(self, f: *const (), ctx: *mut Ctx) -> Rets {
|
||||
let f: extern "C" fn(A, *mut Ctx) -> Rets = mem::transmute(f);
|
||||
let (a,) = self;
|
||||
f(a, ctx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, A: WasmExternType, Rets> Func<'a, (A,), Rets, Safe>
|
||||
where
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
pub fn call(&self, a: A) -> Result<Rets, RuntimeError> {
|
||||
Ok(unsafe { <A as WasmTypeList>::call(a, self.f, self.ctx) })
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_traits {
|
||||
( $struct_name:ident, $( $x:ident ),* ) => {
|
||||
#[repr(C)]
|
||||
pub struct $struct_name <$( $x ),*> ( $( $x ),* );
|
||||
|
||||
impl< $( $x: WasmExternType, )* > WasmTypeList for ( $( $x ),* ) {
|
||||
type CStruct = $struct_name<$( $x ),*>;
|
||||
fn from_c_struct(c_struct: Self::CStruct) -> Self {
|
||||
#[allow(non_snake_case)]
|
||||
let $struct_name ( $( $x ),* ) = c_struct;
|
||||
( $( $x ),* )
|
||||
}
|
||||
fn into_c_struct(self) -> Self::CStruct {
|
||||
#[allow(unused_parens, non_snake_case)]
|
||||
let ( $( $x ),* ) = self;
|
||||
$struct_name ( $( $x ),* )
|
||||
}
|
||||
fn types() -> &'static [Type] {
|
||||
&[$( $x::TYPE, )*]
|
||||
}
|
||||
#[allow(non_snake_case)]
|
||||
unsafe fn call<Rets: WasmTypeList>(self, f: *const (), ctx: *mut Ctx) -> Rets {
|
||||
let f: extern fn( $( $x, )* *mut Ctx) -> Rets::CStruct = mem::transmute(f);
|
||||
#[allow(unused_parens)]
|
||||
let ( $( $x ),* ) = self;
|
||||
let c_struct = f( $( $x, )* ctx);
|
||||
Rets::from_c_struct(c_struct)
|
||||
}
|
||||
}
|
||||
|
||||
impl< $( $x: WasmExternType, )* Rets: WasmTypeList, FN: Fn( $( $x, )* &mut Ctx) -> Rets> ExternalFunction<($( $x ),*), Rets> for FN {
|
||||
#[allow(non_snake_case)]
|
||||
fn to_raw(self) -> *const () {
|
||||
assert_eq!(mem::size_of::<Self>(), 0, "you cannot use a closure that captures state for `Func`.");
|
||||
|
||||
extern fn wrap<$( $x: WasmExternType, )* Rets: WasmTypeList, FN: Fn( $( $x, )* &mut Ctx) -> Rets>( $( $x: $x, )* ctx: &mut Ctx) -> Rets::CStruct {
|
||||
let f: FN = unsafe { mem::transmute_copy(&()) };
|
||||
let rets = f( $( $x, )* ctx);
|
||||
rets.into_c_struct()
|
||||
}
|
||||
|
||||
wrap::<$( $x, )* Rets, Self> as *const ()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, $( $x: WasmExternType, )* Rets> Func<'a, ( $( $x ),* ), Rets, Safe>
|
||||
where
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
#[allow(non_snake_case)]
|
||||
pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
|
||||
#[allow(unused_parens)]
|
||||
Ok(unsafe { <( $( $x ),* ) as WasmTypeList>::call(( $($x),* ), self.f, self.ctx) })
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_traits!(S0,);
|
||||
impl_traits!(S1, A);
|
||||
impl_traits!(S2, A, B);
|
||||
impl_traits!(S3, A, B, C);
|
||||
impl_traits!(S4, A, B, C, D);
|
||||
impl_traits!(S5, A, B, C, D, E);
|
||||
impl_traits!(S6, A, B, C, D, E, F);
|
||||
impl_traits!(S7, A, B, C, D, E, F, G);
|
||||
impl_traits!(S8, A, B, C, D, E, F, G, H);
|
||||
impl_traits!(S9, A, B, C, D, E, F, G, H, I);
|
||||
impl_traits!(S10, A, B, C, D, E, F, G, H, I, J);
|
||||
impl_traits!(S11, A, B, C, D, E, F, G, H, I, J, K);
|
||||
|
||||
impl<'a, Args, Rets, Safety> IsExport for Func<'a, Args, Rets, Safety>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
Safety: Safeness,
|
||||
{
|
||||
fn to_export(&mut self) -> Export {
|
||||
let func = unsafe { FuncPointer::new(self.f as _) };
|
||||
let ctx = Context::Internal;
|
||||
let signature = Arc::new(FuncSig::new(Args::types(), Rets::types()));
|
||||
|
||||
Export::Function {
|
||||
func,
|
||||
ctx,
|
||||
signature,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
#[test]
|
||||
fn test_call() {
|
||||
fn foo(a: i32, b: i32, _ctx: &mut Ctx) -> (i32, i32) {
|
||||
(a, b)
|
||||
}
|
||||
|
||||
let _f = Func::new(foo);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_imports() {
|
||||
use crate::{func, imports};
|
||||
|
||||
fn foo(a: i32, _ctx: &mut Ctx) -> i32 {
|
||||
a
|
||||
}
|
||||
|
||||
let _import_object = imports! {
|
||||
"env" => {
|
||||
"foo" => func!(foo),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user