mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-09 14:18:20 +00:00
Native function now works fully
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
use crate::export::Export;
|
||||
use crate::externals::{Extern, Function /* , Global, Table */, Memory};
|
||||
use crate::externals::{Extern, Function, Global, Memory, Table};
|
||||
use crate::import_object::LikeNamespace;
|
||||
// use crate::native::NativeFunc;
|
||||
use crate::native::NativeFunc;
|
||||
use crate::WasmTypeList;
|
||||
use indexmap::IndexMap;
|
||||
use std::fmt;
|
||||
@@ -118,39 +118,39 @@ impl Exports {
|
||||
}
|
||||
}
|
||||
|
||||
// /// Get an export as a `Global`.
|
||||
// pub fn get_global(&self, name: &str) -> Result<&Global, ExportError> {
|
||||
// self.get(name)
|
||||
// }
|
||||
/// Get an export as a `Global`.
|
||||
pub fn get_global(&self, name: &str) -> Result<&Global, ExportError> {
|
||||
self.get(name)
|
||||
}
|
||||
|
||||
/// Get an export as a `Memory`.
|
||||
pub fn get_memory(&self, name: &str) -> Result<&Memory, ExportError> {
|
||||
self.get(name)
|
||||
}
|
||||
|
||||
// /// Get an export as a `Table`.
|
||||
// pub fn get_table(&self, name: &str) -> Result<&Table, ExportError> {
|
||||
// self.get(name)
|
||||
// }
|
||||
/// Get an export as a `Table`.
|
||||
pub fn get_table(&self, name: &str) -> Result<&Table, ExportError> {
|
||||
self.get(name)
|
||||
}
|
||||
|
||||
/// Get an export as a `Func`.
|
||||
pub fn get_function(&self, name: &str) -> Result<&Function, ExportError> {
|
||||
self.get(name)
|
||||
}
|
||||
|
||||
// /// Get an export as a `NativeFunc`.
|
||||
// pub fn get_native_function<Args, Rets>(
|
||||
// &self,
|
||||
// name: &str,
|
||||
// ) -> Result<NativeFunc<Args, Rets>, ExportError>
|
||||
// where
|
||||
// Args: WasmTypeList,
|
||||
// Rets: WasmTypeList,
|
||||
// {
|
||||
// self.get_function(name)?
|
||||
// .native()
|
||||
// .map_err(|_| ExportError::IncompatibleType)
|
||||
// }
|
||||
/// Get an export as a `NativeFunc`.
|
||||
pub fn get_native_function<Args, Rets>(
|
||||
&self,
|
||||
name: &str,
|
||||
) -> Result<NativeFunc<Args, Rets>, ExportError>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
self.get_function(name)?
|
||||
.native()
|
||||
.map_err(|_| ExportError::IncompatibleType)
|
||||
}
|
||||
|
||||
/// Hack to get this working with nativefunc too
|
||||
pub fn get_with_generics<'a, T, Args, Rets>(&'a self, name: &str) -> Result<T, ExportError>
|
||||
|
||||
97
lib/js-api/src/externals/function.rs
vendored
97
lib/js-api/src/externals/function.rs
vendored
@@ -1,16 +1,16 @@
|
||||
use crate::exports::{ExportError, Exportable};
|
||||
use crate::externals::Extern;
|
||||
use crate::store::Store;
|
||||
use crate::types::{AsJs /* ValFuncRef */, Val};
|
||||
use crate::{FunctionType, ValType};
|
||||
use js_sys::{Array, Function as JSFunction};
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
// use crate::NativeFunc;
|
||||
use crate::types::{param_from_js, AsJs /* ValFuncRef */, Val};
|
||||
use crate::NativeFunc;
|
||||
use crate::RuntimeError;
|
||||
use crate::WasmerEnv;
|
||||
use crate::{FunctionType, ValType};
|
||||
pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv};
|
||||
use js_sys::{Array, Function as JSFunction};
|
||||
use std::iter::FromIterator;
|
||||
use wasm_bindgen::prelude::*;
|
||||
use wasm_bindgen::JsCast;
|
||||
|
||||
use crate::export::{Export, VMFunction};
|
||||
use std::fmt;
|
||||
@@ -18,17 +18,6 @@ use std::fmt;
|
||||
#[repr(C)]
|
||||
pub struct VMFunctionBody(u8);
|
||||
|
||||
#[inline]
|
||||
fn param_from_js(ty: &ValType, js_val: &JsValue) -> Val {
|
||||
match ty {
|
||||
ValType::I32 => Val::I32(js_val.as_f64().unwrap() as _),
|
||||
ValType::I64 => Val::I64(js_val.as_f64().unwrap() as _),
|
||||
ValType::F32 => Val::F32(js_val.as_f64().unwrap() as _),
|
||||
ValType::F64 => Val::F64(js_val.as_f64().unwrap()),
|
||||
_ => unimplemented!("The type is not yet supported in the JS Function API"),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn result_to_js(val: &Val) -> JsValue {
|
||||
match val {
|
||||
@@ -731,42 +720,41 @@ impl Function {
|
||||
/// // This results in an error: `RuntimeError`
|
||||
/// let sum_native = sum.native::<(i32, i32), i64>().unwrap();
|
||||
/// ```
|
||||
// pub fn native<Args, Rets>(&self) -> Result<NativeFunc<Args, Rets>, RuntimeError>
|
||||
// where
|
||||
// Args: WasmTypeList,
|
||||
// Rets: WasmTypeList,
|
||||
// {
|
||||
// unimplemented!();
|
||||
// // // type check
|
||||
// // {
|
||||
// // let expected = self.exported.vm_function.signature.params();
|
||||
// // let given = Args::wasm_types();
|
||||
pub fn native<Args, Rets>(&self) -> Result<NativeFunc<Args, Rets>, RuntimeError>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
// type check
|
||||
{
|
||||
let expected = self.exported.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,
|
||||
// // )));
|
||||
// // }
|
||||
// // }
|
||||
if expected != given {
|
||||
return Err(RuntimeError::from_str(&format!(
|
||||
"given types (`{:?}`) for the function arguments don't match the actual types (`{:?}`)",
|
||||
given,
|
||||
expected,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// // {
|
||||
// // let expected = self.exported.vm_function.signature.results();
|
||||
// // let given = Rets::wasm_types();
|
||||
{
|
||||
let expected = self.exported.ty.results();
|
||||
let given = Rets::wasm_types();
|
||||
|
||||
// // if expected != given {
|
||||
// // // todo: error result types don't match
|
||||
// // return Err(RuntimeError::new(format!(
|
||||
// // "given types (`{:?}`) for the function results don't match the actual types (`{:?}`)",
|
||||
// // given,
|
||||
// // expected,
|
||||
// // )));
|
||||
// // }
|
||||
// // }
|
||||
if expected != given {
|
||||
// todo: error result types don't match
|
||||
return Err(RuntimeError::from_str(&format!(
|
||||
"given types (`{:?}`) for the function results don't match the actual types (`{:?}`)",
|
||||
given,
|
||||
expected,
|
||||
)));
|
||||
}
|
||||
}
|
||||
|
||||
// // Ok(NativeFunc::new(self.store.clone(), self.exported.clone()))
|
||||
// }
|
||||
Ok(NativeFunc::new(self.store.clone(), self.exported.clone()))
|
||||
}
|
||||
|
||||
#[track_caller]
|
||||
fn closures_unsupported_panic() -> ! {
|
||||
@@ -1058,6 +1046,9 @@ mod inner {
|
||||
/// Note that all values are stored in their binary form.
|
||||
type Array: AsMut<[i128]>;
|
||||
|
||||
/// The size of the array
|
||||
fn size() -> u32;
|
||||
|
||||
/// Constructs `Self` based on an array of values.
|
||||
fn from_array(array: Self::Array) -> Self;
|
||||
|
||||
@@ -1279,6 +1270,10 @@ mod inner {
|
||||
|
||||
type Array = [i128; count_idents!( $( $x ),* )];
|
||||
|
||||
fn size() -> u32 {
|
||||
count_idents!( $( $x ),* ) as _
|
||||
}
|
||||
|
||||
fn from_array(array: Self::Array) -> Self {
|
||||
// Unpack items of the array.
|
||||
#[allow(non_snake_case)]
|
||||
@@ -1487,6 +1482,10 @@ mod inner {
|
||||
type CStruct = Self;
|
||||
type Array = [i128; 0];
|
||||
|
||||
fn size() -> u32 {
|
||||
0
|
||||
}
|
||||
|
||||
fn from_array(_: Self::Array) -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
@@ -278,9 +278,6 @@ mod lib {
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
mod cell;
|
||||
mod env;
|
||||
mod error;
|
||||
@@ -293,13 +290,13 @@ mod iterators;
|
||||
mod module;
|
||||
#[cfg(feature = "wasm-types-polyfill")]
|
||||
mod module_info_polyfill;
|
||||
mod resolver;
|
||||
mod wasm_bindgen_polyfill;
|
||||
// mod native;
|
||||
mod native;
|
||||
mod ptr;
|
||||
mod resolver;
|
||||
mod store;
|
||||
mod types;
|
||||
mod utils;
|
||||
mod wasm_bindgen_polyfill;
|
||||
|
||||
/// Implement [`WasmerEnv`] for your type with `#[derive(WasmerEnv)]`.
|
||||
///
|
||||
@@ -316,10 +313,10 @@ pub use crate::externals::{
|
||||
pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace};
|
||||
pub use crate::instance::{Instance, InstantiationError};
|
||||
pub use crate::module::{Module, ModuleTypeHints};
|
||||
pub use wasm_bindgen::JsValue as RuntimeError;
|
||||
// pub use crate::native::NativeFunc;
|
||||
pub use crate::native::NativeFunc;
|
||||
pub use crate::ptr::{Array, Item, WasmPtr};
|
||||
pub use crate::resolver::{ChainableNamedResolver, NamedResolver, NamedResolverChain, Resolver};
|
||||
pub use wasm_bindgen::JsValue as RuntimeError;
|
||||
|
||||
pub use crate::store::{Store, StoreObject};
|
||||
pub use crate::types::{
|
||||
@@ -342,6 +339,9 @@ pub use wat::parse_bytes as wat2wasm;
|
||||
/// Version number of this crate.
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
// #[cfg(test)]
|
||||
// wasm_bindgen_test::wasm_bindgen_test_configure!(run_in_browser);
|
||||
|
||||
// use wasm_bindgen::prelude::*;
|
||||
|
||||
// #[wasm_bindgen]
|
||||
|
||||
@@ -9,18 +9,21 @@
|
||||
//! ```
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::externals::function::{DynamicFunction, VMDynamicFunction};
|
||||
use crate::{FromToNativeWasmType, Function, RuntimeError, Store, WasmTypeList};
|
||||
use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
use wasmer_engine::ExportFunction;
|
||||
// use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
use crate::export::VMFunction;
|
||||
use crate::types::{param_from_js, AsJs};
|
||||
use js_sys::Array;
|
||||
use std::iter::FromIterator;
|
||||
use wasm_bindgen::JsValue;
|
||||
use wasmer_types::NativeWasmType;
|
||||
use wasmer_vm::{VMDynamicFunctionContext, VMFunctionBody, VMFunctionEnvironment, VMFunctionKind};
|
||||
|
||||
/// A WebAssembly function that can be called natively
|
||||
/// (using the Native ABI).
|
||||
#[derive(Clone)]
|
||||
pub struct NativeFunc<Args = (), Rets = ()> {
|
||||
store: Store,
|
||||
exported: ExportFunction,
|
||||
exported: VMFunction,
|
||||
_phantom: PhantomData<(Args, Rets)>,
|
||||
}
|
||||
|
||||
@@ -31,76 +34,16 @@ where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
pub(crate) fn new(store: Store, exported: ExportFunction) -> Self {
|
||||
pub(crate) fn new(store: Store, exported: VMFunction) -> Self {
|
||||
Self {
|
||||
store,
|
||||
exported,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn is_host(&self) -> bool {
|
||||
self.exported.vm_function.instance_ref.is_none()
|
||||
}
|
||||
|
||||
pub(crate) fn vmctx(&self) -> VMFunctionEnvironment {
|
||||
self.exported.vm_function.vmctx
|
||||
}
|
||||
|
||||
pub(crate) fn address(&self) -> *const VMFunctionBody {
|
||||
self.exported.vm_function.address
|
||||
}
|
||||
|
||||
pub(crate) fn arg_kind(&self) -> VMFunctionKind {
|
||||
self.exported.vm_function.kind
|
||||
}
|
||||
|
||||
/// Get access to the backing VM value for this extern. This function is for
|
||||
/// tests it should not be called by users of the Wasmer API.
|
||||
///
|
||||
/// # Safety
|
||||
/// This function is unsafe to call outside of tests for the wasmer crate
|
||||
/// because there is no stability guarantee for the returned type and we may
|
||||
/// make breaking changes to it at any time or remove this method.
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn get_vm_function(&self) -> &wasmer_vm::VMFunction {
|
||||
&self.exported.vm_function
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
impl<Args, Rets> From<&NativeFunc<Args, Rets>> for VMFunction
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
fn from(other: &NativeFunc<Args, Rets>) -> Self {
|
||||
let signature = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
|
||||
Self {
|
||||
address: other.address,
|
||||
vmctx: other.vmctx,
|
||||
signature,
|
||||
kind: other.arg_kind,
|
||||
call_trampoline: None,
|
||||
instance_ref: None,
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
impl<Args: WasmTypeList, Rets: WasmTypeList> Clone for NativeFunc<Args, Rets> {
|
||||
fn clone(&self) -> Self {
|
||||
let mut exported = self.exported.clone();
|
||||
exported.vm_function.upgrade_instance_ref().unwrap();
|
||||
|
||||
Self {
|
||||
store: self.store.clone(),
|
||||
exported,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<Args, Rets> From<&NativeFunc<Args, Rets>> for ExportFunction
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
@@ -133,92 +76,34 @@ macro_rules! impl_native_traits {
|
||||
{
|
||||
/// Call the typed func and return results.
|
||||
pub fn call(&self, $( $x: $x, )* ) -> Result<Rets, RuntimeError> {
|
||||
if !self.is_host() {
|
||||
// We assume the trampoline is always going to be present for
|
||||
// Wasm functions
|
||||
let trampoline = self.exported.vm_function.call_trampoline.expect("Call trampoline not found in wasm function");
|
||||
// TODO: when `const fn` related features mature more, we can declare a single array
|
||||
// of the correct size here.
|
||||
let mut params_list = [ $( $x.to_native().to_binary() ),* ];
|
||||
let mut rets_list_array = Rets::empty_array();
|
||||
let rets_list = rets_list_array.as_mut();
|
||||
let using_rets_array;
|
||||
let args_rets: &mut [i128] = if params_list.len() > rets_list.len() {
|
||||
using_rets_array = false;
|
||||
params_list.as_mut()
|
||||
} else {
|
||||
using_rets_array = true;
|
||||
for (i, &arg) in params_list.iter().enumerate() {
|
||||
rets_list[i] = arg;
|
||||
}
|
||||
rets_list.as_mut()
|
||||
};
|
||||
unsafe {
|
||||
wasmer_vm::wasmer_call_trampoline(
|
||||
&self.store,
|
||||
self.vmctx(),
|
||||
trampoline,
|
||||
self.address(),
|
||||
args_rets.as_mut_ptr() as *mut u8,
|
||||
)
|
||||
}?;
|
||||
let num_rets = rets_list.len();
|
||||
if !using_rets_array && num_rets > 0 {
|
||||
let src_pointer = params_list.as_ptr();
|
||||
let rets_list = &mut rets_list_array.as_mut()[0] as *mut i128;
|
||||
unsafe {
|
||||
// TODO: we can probably remove this copy by doing some clever `transmute`s.
|
||||
// we know it's not overlapping because `using_rets_array` is false
|
||||
std::ptr::copy_nonoverlapping(src_pointer,
|
||||
rets_list,
|
||||
num_rets);
|
||||
}
|
||||
}
|
||||
Ok(Rets::from_array(rets_list_array))
|
||||
// TODO: When the Host ABI and Wasm ABI are the same, we could do this instead:
|
||||
// but we can't currently detect whether that's safe.
|
||||
//
|
||||
// let results = unsafe {
|
||||
// wasmer_vm::catch_traps_with_result(self.vmctx, || {
|
||||
// let f = std::mem::transmute::<_, unsafe extern "C" fn( *mut VMContext, $( $x, )*) -> Rets::CStruct>(self.address());
|
||||
// // We always pass the vmctx
|
||||
// f( self.vmctx, $( $x, )* )
|
||||
// }).map_err(RuntimeError::from_trap)?
|
||||
// };
|
||||
// Ok(Rets::from_c_struct(results))
|
||||
|
||||
}
|
||||
else {
|
||||
match self.arg_kind() {
|
||||
VMFunctionKind::Static => {
|
||||
let results = catch_unwind(AssertUnwindSafe(|| unsafe {
|
||||
let f = std::mem::transmute::<_, unsafe extern "C" fn( VMFunctionEnvironment, $( $x, )*) -> Rets::CStruct>(self.address());
|
||||
// We always pass the vmctx
|
||||
f( self.vmctx(), $( $x, )* )
|
||||
})).map_err(|e| RuntimeError::new(format!("{:?}", e)))?;
|
||||
Ok(Rets::from_c_struct(results))
|
||||
},
|
||||
VMFunctionKind::Dynamic => {
|
||||
let params_list = [ $( $x.to_native().to_value() ),* ];
|
||||
let results = {
|
||||
type VMContextWithEnv = VMDynamicFunctionContext<DynamicFunction<std::ffi::c_void>>;
|
||||
unsafe {
|
||||
let ctx = self.vmctx().host_env as *mut VMContextWithEnv;
|
||||
(*ctx).ctx.call(¶ms_list)?
|
||||
}
|
||||
};
|
||||
let params_list: Vec<JsValue> = vec![ $( JsValue::from_f64($x.to_native().to_binary() as f64) ),* ];
|
||||
let results = self.exported.function.apply(
|
||||
&JsValue::UNDEFINED,
|
||||
&Array::from_iter(params_list.iter())
|
||||
).unwrap();
|
||||
let mut rets_list_array = Rets::empty_array();
|
||||
let mut_rets = rets_list_array.as_mut() as *mut [i128] as *mut i128;
|
||||
for (i, ret) in results.iter().enumerate() {
|
||||
match Rets::size() {
|
||||
0 => {},
|
||||
1 => unsafe {
|
||||
let ty = Rets::wasm_types()[0];
|
||||
let val = param_from_js(&ty, &results);
|
||||
val.write_value_to(mut_rets);
|
||||
}
|
||||
n => {
|
||||
let results: Array = results.into();
|
||||
for (i, ret_type) in Rets::wasm_types().iter().enumerate() {
|
||||
let ret = results.get(i as u32);
|
||||
unsafe {
|
||||
ret.write_value_to(mut_rets.add(i));
|
||||
let val = param_from_js(&ret_type, &ret);
|
||||
let p = mut_rets.add(i);
|
||||
val.write_value_to(mut_rets.add(i));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(Rets::from_array(rets_list_array))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -232,10 +117,6 @@ macro_rules! impl_native_traits {
|
||||
use crate::exports::Exportable;
|
||||
crate::Function::get_self_from_extern(_extern)?.native().map_err(|_| crate::exports::ExportError::IncompatibleType)
|
||||
}
|
||||
|
||||
fn into_weak_instance_ref(&mut self) {
|
||||
self.exported.vm_function.instance_ref.as_mut().map(|v| *v = v.downgrade());
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@@ -22,6 +22,17 @@ pub trait AsJs {
|
||||
fn as_jsvalue(&self) -> JsValue;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn param_from_js(ty: &ValType, js_val: &JsValue) -> Val {
|
||||
match ty {
|
||||
ValType::I32 => Val::I32(js_val.as_f64().unwrap() as _),
|
||||
ValType::I64 => Val::I64(js_val.as_f64().unwrap() as _),
|
||||
ValType::F32 => Val::F32(js_val.as_f64().unwrap() as _),
|
||||
ValType::F64 => Val::F64(js_val.as_f64().unwrap()),
|
||||
_ => unimplemented!("The type is not yet supported in the JS Function API"),
|
||||
}
|
||||
}
|
||||
|
||||
impl AsJs for Val {
|
||||
fn as_jsvalue(&self) -> JsValue {
|
||||
match self {
|
||||
|
||||
@@ -327,39 +327,37 @@ fn function_new_dynamic_env() {
|
||||
assert_eq!(function.ty().results(), [Type::I32, Type::F32, Type::F64]);
|
||||
}
|
||||
|
||||
// #[test]
|
||||
// fn native_function_works() -> Result<()> {
|
||||
// let store = Store::default();
|
||||
// let function = Function::new_native(&store, || {});
|
||||
// let native_function: NativeFunc<(), ()> = function.native().unwrap();
|
||||
// let result = native_function.call();
|
||||
// assert!(result.is_ok());
|
||||
#[wasm_bindgen_test]
|
||||
fn native_function_works() {
|
||||
let store = Store::default();
|
||||
let function = Function::new_native(&store, || {});
|
||||
let native_function: NativeFunc<(), ()> = function.native().unwrap();
|
||||
let result = native_function.call();
|
||||
assert!(result.is_ok());
|
||||
|
||||
// let function = Function::new_native(&store, |a: i32| -> i32 { a + 1 });
|
||||
// let native_function: NativeFunc<i32, i32> = function.native().unwrap();
|
||||
// assert_eq!(native_function.call(3).unwrap(), 4);
|
||||
let function = Function::new_native(&store, |a: i32| -> i32 { a + 1 });
|
||||
let native_function: NativeFunc<i32, i32> = function.native().unwrap();
|
||||
assert_eq!(native_function.call(3).unwrap(), 4);
|
||||
|
||||
// fn rust_abi(a: i32, b: i64, c: f32, d: f64) -> u64 {
|
||||
// (a as u64 * 1000) + (b as u64 * 100) + (c as u64 * 10) + (d as u64)
|
||||
// }
|
||||
// let function = Function::new_native(&store, rust_abi);
|
||||
// let native_function: NativeFunc<(i32, i64, f32, f64), u64> = function.native().unwrap();
|
||||
// assert_eq!(native_function.call(8, 4, 1.5, 5.).unwrap(), 8415);
|
||||
// fn rust_abi(a: i32, b: i64, c: f32, d: f64) -> u64 {
|
||||
// (a as u64 * 1000) + (b as u64 * 100) + (c as u64 * 10) + (d as u64)
|
||||
// }
|
||||
// let function = Function::new_native(&store, rust_abi);
|
||||
// let native_function: NativeFunc<(i32, i64, f32, f64), u64> = function.native().unwrap();
|
||||
// assert_eq!(native_function.call(8, 4, 1.5, 5.).unwrap(), 8415);
|
||||
|
||||
// let function = Function::new_native(&store, || -> i32 { 1 });
|
||||
// let native_function: NativeFunc<(), i32> = function.native().unwrap();
|
||||
// assert_eq!(native_function.call().unwrap(), 1);
|
||||
let function = Function::new_native(&store, || -> i32 { 1 });
|
||||
let native_function: NativeFunc<(), i32> = function.native().unwrap();
|
||||
assert_eq!(native_function.call().unwrap(), 1);
|
||||
|
||||
// let function = Function::new_native(&store, |_a: i32| {});
|
||||
// let native_function: NativeFunc<i32, ()> = function.native().unwrap();
|
||||
// assert!(native_function.call(4).is_ok());
|
||||
let function = Function::new_native(&store, |_a: i32| {});
|
||||
let native_function: NativeFunc<i32, ()> = function.native().unwrap();
|
||||
assert!(native_function.call(4).is_ok());
|
||||
|
||||
// let function = Function::new_native(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
|
||||
// let native_function: NativeFunc<(), (i32, i64, f32, f64)> = function.native().unwrap();
|
||||
// assert_eq!(native_function.call().unwrap(), (1, 2, 3.0, 4.0));
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
// let function = Function::new_native(&store, || -> (i32, i64, f32, f64) { (1, 2, 3.0, 4.0) });
|
||||
// let native_function: NativeFunc<(), (i32, i64, f32, f64)> = function.native().unwrap();
|
||||
// assert_eq!(native_function.call().unwrap(), (1, 2, 3.0, 4.0));
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn function_outlives_instance() {
|
||||
|
||||
Reference in New Issue
Block a user