use crate::{
error::HostFuncError, io::WasmValTypeList, CallingFrame, FuncType, Global, Memory, Table,
WasmEdgeResult, WasmValue,
};
use wasmedge_sys::{self as sys, AsImport};
#[derive(Debug, Default)]
pub struct ImportObjectBuilder {
funcs: Vec<(String, sys::Function)>,
globals: Vec<(String, sys::Global)>,
memories: Vec<(String, sys::Memory)>,
tables: Vec<(String, sys::Table)>,
}
impl ImportObjectBuilder {
pub fn new() -> Self {
Self {
funcs: Vec::new(),
globals: Vec::new(),
memories: Vec::new(),
tables: Vec::new(),
}
}
pub fn with_func<Args, Rets>(
mut self,
name: impl AsRef<str>,
real_func: impl Fn(CallingFrame, Vec<WasmValue>) -> Result<Vec<WasmValue>, HostFuncError>
+ Send
+ Sync
+ 'static,
) -> WasmEdgeResult<Self>
where
Args: WasmValTypeList,
Rets: WasmValTypeList,
{
let boxed_func = Box::new(real_func);
let args = Args::wasm_types();
let returns = Rets::wasm_types();
let ty = FuncType::new(Some(args.to_vec()), Some(returns.to_vec()));
let inner_func = sys::Function::create(&ty.into(), boxed_func, 0)?;
self.funcs.push((name.as_ref().to_owned(), inner_func));
Ok(self)
}
pub fn with_func_by_type(
mut self,
name: impl AsRef<str>,
ty: FuncType,
real_func: impl Fn(CallingFrame, Vec<WasmValue>) -> Result<Vec<WasmValue>, HostFuncError>
+ Send
+ Sync
+ 'static,
) -> WasmEdgeResult<Self> {
let boxed_func = Box::new(real_func);
let inner_func = sys::Function::create(&ty.into(), boxed_func, 0)?;
self.funcs.push((name.as_ref().to_owned(), inner_func));
Ok(self)
}
#[cfg(feature = "async")]
pub fn with_func_async<Args, Rets>(
mut self,
name: impl AsRef<str>,
real_func: impl Fn(
CallingFrame,
Vec<WasmValue>,
) -> Box<
dyn std::future::Future<
Output = Result<Vec<WasmValue>, crate::error::HostFuncError>,
> + Send,
> + Send
+ Sync
+ 'static,
) -> WasmEdgeResult<Self>
where
Args: WasmValTypeList,
Rets: WasmValTypeList,
{
let boxed_func = Box::new(real_func);
let args = Args::wasm_types();
let returns = Rets::wasm_types();
let ty = FuncType::new(Some(args.to_vec()), Some(returns.to_vec()));
let inner_func = sys::Function::create_async(&ty.into(), boxed_func, 0)?;
self.funcs.push((name.as_ref().to_owned(), inner_func));
Ok(self)
}
pub fn with_global(mut self, name: impl AsRef<str>, global: Global) -> WasmEdgeResult<Self> {
self.globals.push((name.as_ref().to_owned(), global.inner));
Ok(self)
}
pub fn with_memory(mut self, name: impl AsRef<str>, memory: Memory) -> WasmEdgeResult<Self> {
self.memories.push((name.as_ref().to_owned(), memory.inner));
Ok(self)
}
pub fn with_table(mut self, name: impl AsRef<str>, table: Table) -> WasmEdgeResult<Self> {
self.tables.push((name.as_ref().to_owned(), table.inner));
Ok(self)
}
pub fn build(self, name: impl AsRef<str>) -> WasmEdgeResult<ImportObject> {
let mut inner = sys::ImportModule::create(name.as_ref())?;
for (name, func) in self.funcs.into_iter() {
inner.add_func(name, func);
}
for (name, global) in self.globals.into_iter() {
inner.add_global(name, global);
}
for (name, memory) in self.memories.into_iter() {
inner.add_memory(name, memory);
}
for (name, table) in self.tables.into_iter() {
inner.add_table(name, table);
}
Ok(ImportObject(sys::ImportObject::Import(inner)))
}
pub fn build_as_wasi<'a>(
self,
args: Option<Vec<&'a str>>,
envs: Option<Vec<&'a str>>,
preopens: Option<Vec<&'a str>>,
) -> WasmEdgeResult<ImportObject> {
let mut inner = sys::WasiModule::create(args, envs, preopens)?;
for (name, func) in self.funcs.into_iter() {
inner.add_func(name, func);
}
for (name, global) in self.globals.into_iter() {
inner.add_global(name, global);
}
for (name, memory) in self.memories.into_iter() {
inner.add_memory(name, memory);
}
for (name, table) in self.tables.into_iter() {
inner.add_table(name, table);
}
Ok(ImportObject(sys::ImportObject::Wasi(inner)))
}
#[cfg(target_os = "linux")]
pub fn build_as_wasmedge_process(
self,
allowed_cmds: Option<Vec<&str>>,
allowed: bool,
) -> WasmEdgeResult<ImportObject> {
let mut inner = sys::WasmEdgeProcessModule::create(allowed_cmds, allowed)?;
for (name, func) in self.funcs.into_iter() {
inner.add_func(name, func);
}
for (name, global) in self.globals.into_iter() {
inner.add_global(name, global);
}
for (name, memory) in self.memories.into_iter() {
inner.add_memory(name, memory);
}
for (name, table) in self.tables.into_iter() {
inner.add_table(name, table);
}
Ok(ImportObject(sys::ImportObject::WasmEdgeProcess(inner)))
}
#[cfg(all(target_os = "linux", feature = "wasi_nn", target_arch = "x86_64"))]
pub fn build_as_wasi_nn(self) -> WasmEdgeResult<ImportObject> {
let mut inner = sys::WasiNnModule::create()?;
for (name, func) in self.funcs.into_iter() {
inner.add_func(name, func);
}
for (name, global) in self.globals.into_iter() {
inner.add_global(name, global);
}
for (name, memory) in self.memories.into_iter() {
inner.add_memory(name, memory);
}
for (name, table) in self.tables.into_iter() {
inner.add_table(name, table);
}
Ok(ImportObject(sys::ImportObject::Nn(inner)))
}
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
pub fn build_as_wasi_crypto_common(self) -> WasmEdgeResult<ImportObject> {
let mut inner = sys::WasiCryptoCommonModule::create()?;
for (name, func) in self.funcs.into_iter() {
inner.add_func(name, func);
}
for (name, global) in self.globals.into_iter() {
inner.add_global(name, global);
}
for (name, memory) in self.memories.into_iter() {
inner.add_memory(name, memory);
}
for (name, table) in self.tables.into_iter() {
inner.add_table(name, table);
}
Ok(ImportObject(sys::ImportObject::Crypto(
sys::WasiCrypto::Common(inner),
)))
}
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
pub fn build_as_wasi_crypto_asymmetric_common(self) -> WasmEdgeResult<ImportObject> {
let mut inner = sys::WasiCryptoAsymmetricCommonModule::create()?;
for (name, func) in self.funcs.into_iter() {
inner.add_func(name, func);
}
for (name, global) in self.globals.into_iter() {
inner.add_global(name, global);
}
for (name, memory) in self.memories.into_iter() {
inner.add_memory(name, memory);
}
for (name, table) in self.tables.into_iter() {
inner.add_table(name, table);
}
Ok(ImportObject(sys::ImportObject::Crypto(
sys::WasiCrypto::AsymmetricCommon(inner),
)))
}
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
pub fn build_as_wasi_crypto_symmetric(self) -> WasmEdgeResult<ImportObject> {
let mut inner = sys::WasiCryptoSymmetricModule::create()?;
for (name, func) in self.funcs.into_iter() {
inner.add_func(name, func);
}
for (name, global) in self.globals.into_iter() {
inner.add_global(name, global);
}
for (name, memory) in self.memories.into_iter() {
inner.add_memory(name, memory);
}
for (name, table) in self.tables.into_iter() {
inner.add_table(name, table);
}
Ok(ImportObject(sys::ImportObject::Crypto(
sys::WasiCrypto::SymmetricOptionations(inner),
)))
}
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
pub fn build_as_wasi_crypto_kx(self) -> WasmEdgeResult<ImportObject> {
let mut inner = sys::WasiCryptoKxModule::create()?;
for (name, func) in self.funcs.into_iter() {
inner.add_func(name, func);
}
for (name, global) in self.globals.into_iter() {
inner.add_global(name, global);
}
for (name, memory) in self.memories.into_iter() {
inner.add_memory(name, memory);
}
for (name, table) in self.tables.into_iter() {
inner.add_table(name, table);
}
Ok(ImportObject(sys::ImportObject::Crypto(
sys::WasiCrypto::KeyExchange(inner),
)))
}
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
pub fn build_as_wasi_crypto_signatures(self) -> WasmEdgeResult<ImportObject> {
let mut inner = sys::WasiCryptoSignaturesModule::create()?;
for (name, func) in self.funcs.into_iter() {
inner.add_func(name, func);
}
for (name, global) in self.globals.into_iter() {
inner.add_global(name, global);
}
for (name, memory) in self.memories.into_iter() {
inner.add_memory(name, memory);
}
for (name, table) in self.tables.into_iter() {
inner.add_table(name, table);
}
Ok(ImportObject(sys::ImportObject::Crypto(
sys::WasiCrypto::Signatures(inner),
)))
}
}
#[derive(Debug)]
pub struct ImportObject(pub(crate) sys::ImportObject);
impl ImportObject {
pub fn name(&self) -> String {
match &self.0 {
sys::ImportObject::Import(import) => import.name().into(),
sys::ImportObject::Wasi(wasi) => wasi.name().into(),
#[cfg(target_os = "linux")]
sys::ImportObject::WasmEdgeProcess(wasmedge_process) => wasmedge_process.name().into(),
#[cfg(all(target_os = "linux", feature = "wasi_nn", target_arch = "x86_64"))]
sys::ImportObject::Nn(module) => module.name().into(),
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
sys::ImportObject::Crypto(sys::WasiCrypto::Common(module)) => module.name().into(),
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
sys::ImportObject::Crypto(sys::WasiCrypto::AsymmetricCommon(module)) => {
module.name().into()
}
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
sys::ImportObject::Crypto(sys::WasiCrypto::SymmetricOptionations(module)) => {
module.name().into()
}
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
sys::ImportObject::Crypto(sys::WasiCrypto::KeyExchange(module)) => module.name().into(),
#[cfg(all(target_os = "linux", feature = "wasi_crypto"))]
sys::ImportObject::Crypto(sys::WasiCrypto::Signatures(module)) => module.name().into(),
}
}
pub(crate) fn inner_ref(&self) -> &sys::ImportObject {
&self.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[cfg(target_os = "linux")]
use crate::PluginManager;
use crate::{
config::{CommonConfigOptions, ConfigBuilder},
error::{CoreError, CoreInstantiationError, GlobalError, WasmEdgeError},
params,
types::Val,
Executor, Global, GlobalType, Memory, MemoryType, Mutability, RefType, Statistics, Store,
Table, TableType, ValType, WasmVal, WasmValue,
};
use std::{
sync::{Arc, Mutex},
thread,
};
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_import_builder() {
let result = ImportObjectBuilder::default().build("extern");
assert!(result.is_ok());
let import = result.unwrap();
assert_eq!(import.name(), "extern");
}
#[test]
#[cfg(unix)]
#[allow(clippy::assertions_on_result_states)]
fn test_import_builder_wasi() {
let result = ImportObjectBuilder::default().build_as_wasi(None, None, None);
assert!(result.is_ok());
let import = result.unwrap();
assert_eq!(import.name(), "wasi_snapshot_preview1");
}
#[test]
#[cfg(target_os = "linux")]
#[allow(clippy::assertions_on_result_states)]
fn test_import_builder_wasmedge_process() {
PluginManager::load_from_default_paths();
let result = ImportObjectBuilder::default().build_as_wasmedge_process(None, false);
assert!(result.is_ok());
let import = result.unwrap();
assert_eq!(import.name(), "wasmedge_process");
}
#[test]
#[cfg(target_os = "linux")]
#[allow(clippy::assertions_on_result_states)]
fn test_import_new_wasmedgeprocess() {
PluginManager::load_from_default_paths();
let result = ImportObjectBuilder::new()
.with_func::<(i32, i32), i32>("add", real_add)
.expect("failed to add host func")
.build_as_wasmedge_process(None, false);
assert!(result.is_ok());
let process_import = result.unwrap();
let result = ConfigBuilder::new(CommonConfigOptions::default()).build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Statistics::new();
assert!(result.is_ok());
let mut stat = result.unwrap();
let result = Executor::new(Some(&config), Some(&mut stat));
assert!(result.is_ok());
let mut executor = result.unwrap();
let result = Store::new();
assert!(result.is_ok());
let mut store = result.unwrap();
let result = store.register_import_module(&mut executor, &process_import);
assert!(result.is_ok());
assert_eq!(store.named_instance_count(), 1);
let result = store.instance_names();
assert!(result.is_some());
assert_eq!(result.unwrap(), ["wasmedge_process"]);
let result = store.module_instance("wasmedge_process");
assert!(result.is_some());
let instance = result.unwrap();
let result = instance.func("add");
assert!(result.is_some());
let result = ImportObjectBuilder::default().build_as_wasmedge_process(None, false);
assert!(result.is_ok());
let import_process = result.unwrap();
let result = store.register_import_module(&mut executor, &import_process);
assert!(result.is_err());
assert_eq!(
result.unwrap_err(),
Box::new(WasmEdgeError::Core(CoreError::Instantiation(
CoreInstantiationError::ModuleNameConflict
)))
);
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_import_new_wasi() {
let result = ImportObjectBuilder::new()
.with_func::<(i32, i32), i32>("add", real_add)
.expect("failed to add host func")
.build_as_wasi(None, None, None);
assert!(result.is_ok());
let wasi_import = result.unwrap();
let result = ConfigBuilder::new(CommonConfigOptions::default()).build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Statistics::new();
assert!(result.is_ok());
let mut stat = result.unwrap();
let result = Executor::new(Some(&config), Some(&mut stat));
assert!(result.is_ok());
let mut executor = result.unwrap();
let result = Store::new();
assert!(result.is_ok());
let mut store = result.unwrap();
let result = store.register_import_module(&mut executor, &wasi_import);
assert!(result.is_ok());
assert_eq!(store.named_instance_count(), 1);
let result = store.instance_names();
assert!(result.is_some());
assert_eq!(result.unwrap(), ["wasi_snapshot_preview1"]);
let result = ImportObjectBuilder::default().build_as_wasi(None, None, None);
assert!(result.is_ok());
let wasi_import = result.unwrap();
let result = store.register_import_module(&mut executor, &wasi_import);
assert!(result.is_err());
assert_eq!(
result.unwrap_err(),
Box::new(WasmEdgeError::Core(CoreError::Instantiation(
CoreInstantiationError::ModuleNameConflict
)))
);
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_import_add_func() {
fn real_add(
_frame: CallingFrame,
inputs: Vec<WasmValue>,
) -> std::result::Result<Vec<WasmValue>, HostFuncError> {
if inputs.len() != 2 {
return Err(HostFuncError::User(1));
}
let a = if inputs[0].ty() == ValType::I32 {
inputs[0].to_i32()
} else {
return Err(HostFuncError::User(2));
};
let b = if inputs[1].ty() == ValType::I32 {
inputs[1].to_i32()
} else {
return Err(HostFuncError::User(3));
};
let c = a + b;
Ok(vec![WasmValue::from_i32(c)])
}
let result = ImportObjectBuilder::new()
.with_func::<(i32, i32), i32>("add", real_add)
.expect("failed to add host func")
.build("extern");
assert!(result.is_ok());
let import = result.unwrap();
let result = ConfigBuilder::new(CommonConfigOptions::default()).build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Statistics::new();
assert!(result.is_ok());
let mut stat = result.unwrap();
let result = Executor::new(Some(&config), Some(&mut stat));
assert!(result.is_ok());
let mut executor = result.unwrap();
let result = Store::new();
assert!(result.is_ok());
let mut store = result.unwrap();
let result = store.register_import_module(&mut executor, &import);
assert!(result.is_ok());
let result = store.module_instance("extern");
assert!(result.is_some());
let instance = result.unwrap();
let result = instance.func("add");
assert!(result.is_some());
let host_func = result.unwrap();
let result = host_func.ty();
assert!(result.is_ok());
let func_ty = result.unwrap();
assert!(func_ty.args().is_some());
assert_eq!(func_ty.args().unwrap(), [ValType::I32; 2]);
assert!(func_ty.returns().is_some());
assert_eq!(func_ty.returns().unwrap(), [ValType::I32]);
let returns = host_func.call(&mut executor, params![1, 2]).unwrap();
assert_eq!(returns[0].to_i32(), 3);
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_import_add_memory() {
let result = MemoryType::new(10, Some(20), false);
assert!(result.is_ok());
let memory_type = result.unwrap();
let result = Memory::new(memory_type);
assert!(result.is_ok());
let memory = result.unwrap();
let result = ImportObjectBuilder::new()
.with_memory("memory", memory)
.expect("failed to add memory")
.build("extern");
assert!(result.is_ok());
let import = result.unwrap();
let result = ConfigBuilder::new(CommonConfigOptions::default()).build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Statistics::new();
assert!(result.is_ok());
let mut stat = result.unwrap();
let result = Executor::new(Some(&config), Some(&mut stat));
assert!(result.is_ok());
let mut executor = result.unwrap();
let result = Store::new();
assert!(result.is_ok());
let mut store = result.unwrap();
let result = store.module_instance("extern");
assert!(result.is_none());
let result = store.register_import_module(&mut executor, &import);
assert!(result.is_ok());
let result = store.module_instance("extern");
assert!(result.is_some());
let instance = result.unwrap();
let result = instance.memory("memory");
assert!(result.is_some());
let mut memory = result.unwrap();
assert!(memory.name().is_some());
assert_eq!(memory.name().unwrap(), "memory");
assert_eq!(memory.mod_name(), Some("extern"));
assert_eq!(memory.size(), 10);
let result = memory.ty();
assert!(result.is_ok());
let ty = result.unwrap();
assert_eq!(ty.minimum(), 10);
assert_eq!(ty.maximum(), Some(20));
let result = memory.grow(5);
assert!(result.is_ok());
assert_eq!(memory.size(), 15);
let result = instance.memory("memory");
assert!(result.is_some());
let memory = result.unwrap();
assert_eq!(memory.size(), 15);
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_import_add_global() {
let result = Global::new(
GlobalType::new(ValType::I32, Mutability::Const),
Val::I32(1314),
);
assert!(result.is_ok());
let global_const = result.unwrap();
let result = Global::new(
GlobalType::new(ValType::F32, Mutability::Var),
Val::F32(13.14),
);
assert!(result.is_ok());
let global_var = result.unwrap();
let result = ImportObjectBuilder::new()
.with_global("const-global", global_const)
.expect("failed to add const-global")
.with_global("var-global", global_var)
.expect("failed to add var-global")
.build("extern");
assert!(result.is_ok());
let import = result.unwrap();
let result = ConfigBuilder::new(CommonConfigOptions::default()).build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Statistics::new();
assert!(result.is_ok());
let mut stat = result.unwrap();
let result = Executor::new(Some(&config), Some(&mut stat));
assert!(result.is_ok());
let mut executor = result.unwrap();
let result = Store::new();
assert!(result.is_ok());
let mut store = result.unwrap();
let result = store.register_import_module(&mut executor, &import);
assert!(result.is_ok());
let result = store.module_instance("extern");
assert!(result.is_some());
let instance = result.unwrap();
let result = instance.global("const-global");
assert!(result.is_some());
let mut const_global = result.unwrap();
assert!(const_global.name().is_some());
assert_eq!(const_global.name().unwrap(), "const-global");
assert!(const_global.mod_name().is_some());
assert_eq!(const_global.mod_name().unwrap(), "extern");
let result = const_global.ty();
assert!(result.is_ok());
let ty = result.unwrap();
assert_eq!(ty.value_ty(), ValType::I32);
assert_eq!(ty.mutability(), Mutability::Const);
if let Val::I32(value) = const_global.get_value() {
assert_eq!(value, 1314);
}
let result = const_global.set_value(Val::I32(314));
assert!(result.is_err());
assert_eq!(
result.unwrap_err(),
Box::new(WasmEdgeError::Global(GlobalError::ModifyConst))
);
let result = store.module_instance("extern");
assert!(result.is_some());
let instance = result.unwrap();
let result = instance.global("var-global");
assert!(result.is_some());
let mut var_global = result.unwrap();
assert!(var_global.name().is_some());
assert_eq!(var_global.name().unwrap(), "var-global");
assert!(var_global.mod_name().is_some());
assert_eq!(var_global.mod_name().unwrap(), "extern");
let result = var_global.ty();
assert!(result.is_ok());
let ty = result.unwrap();
assert_eq!(ty.value_ty(), ValType::F32);
assert_eq!(ty.mutability(), Mutability::Var);
if let Val::F32(value) = var_global.get_value() {
assert_eq!(value, 13.14);
}
let result = var_global.set_value(Val::F32(1.314));
assert!(result.is_ok());
let result = instance.global("var-global");
assert!(result.is_some());
let var_global = result.unwrap();
if let Val::F32(value) = var_global.get_value() {
assert_eq!(value, 1.314);
}
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_import_add_table() {
let result = Table::new(TableType::new(RefType::FuncRef, 10, Some(20)));
assert!(result.is_ok());
let table = result.unwrap();
let result = ImportObjectBuilder::new()
.with_func::<(i32, i32), i32>("add", real_add)
.expect("failed to add host func")
.with_table("table", table)
.expect("failed to add table")
.build("extern");
assert!(result.is_ok());
let import = result.unwrap();
let result = ConfigBuilder::new(CommonConfigOptions::default()).build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Statistics::new();
assert!(result.is_ok());
let mut stat = result.unwrap();
let result = Executor::new(Some(&config), Some(&mut stat));
assert!(result.is_ok());
let mut executor = result.unwrap();
let result = Store::new();
assert!(result.is_ok());
let mut store = result.unwrap();
let result = store.register_import_module(&mut executor, &import);
assert!(result.is_ok());
let result = store.module_instance("extern");
assert!(result.is_some());
let instance = result.unwrap();
let result = instance.func("add");
assert!(result.is_some());
let host_func = result.unwrap();
let result = instance.table("table");
assert!(result.is_some());
let mut table = result.unwrap();
assert!(table.name().is_some());
assert_eq!(table.name().unwrap(), "table");
assert!(table.mod_name().is_some());
assert_eq!(table.mod_name().unwrap(), "extern");
assert_eq!(table.size(), 10);
let result = table.ty();
assert!(result.is_ok());
let ty = result.unwrap();
assert_eq!(ty.elem_ty(), RefType::FuncRef);
assert_eq!(ty.minimum(), 10);
assert_eq!(ty.maximum(), Some(20));
let result = table.get(0);
assert!(result.is_ok());
if let Val::FuncRef(func_ref) = result.unwrap() {
assert!(func_ref.is_none());
}
let func_ref = host_func.as_ref();
let result = table.set(0, Val::FuncRef(Some(func_ref)));
assert!(result.is_ok());
let result = table.get(0);
assert!(result.is_ok());
if let Val::FuncRef(func_ref) = result.unwrap() {
assert!(func_ref.is_some());
let func_ref = func_ref.unwrap();
let result = func_ref.ty();
assert!(result.is_ok());
let func_ty = result.unwrap();
assert!(func_ty.args().is_some());
assert_eq!(func_ty.args().unwrap(), [ValType::I32; 2]);
assert!(func_ty.returns().is_some());
assert_eq!(func_ty.returns().unwrap(), [ValType::I32]);
}
let result = store.module_instance("extern");
assert!(result.is_some());
let instance = result.unwrap();
let result = instance.table("table");
assert!(result.is_some());
let table = result.unwrap();
let result = table.get(0);
assert!(result.is_ok());
if let Val::FuncRef(func_ref) = result.unwrap() {
assert!(func_ref.is_some());
let func_ref = func_ref.unwrap();
let result = func_ref.ty();
assert!(result.is_ok());
let func_ty = result.unwrap();
assert!(func_ty.args().is_some());
assert_eq!(func_ty.args().unwrap(), [ValType::I32; 2]);
assert!(func_ty.returns().is_some());
assert_eq!(func_ty.returns().unwrap(), [ValType::I32]);
}
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_import_send() {
let result = Global::new(
GlobalType::new(ValType::F32, Mutability::Const),
Val::F32(3.5),
);
assert!(result.is_ok());
let global_const = result.unwrap();
let result = MemoryType::new(10, Some(20), false);
assert!(result.is_ok());
let memory_type = result.unwrap();
let result = Memory::new(memory_type);
assert!(result.is_ok());
let memory = result.unwrap();
let result = Table::new(TableType::new(RefType::FuncRef, 10, Some(20)));
assert!(result.is_ok());
let table = result.unwrap();
let result = ImportObjectBuilder::new()
.with_func::<(i32, i32), i32>("add", real_add)
.expect("failed to add host function")
.with_global("global", global_const)
.expect("failed to add const global")
.with_memory("memory", memory)
.expect("failed to add memory")
.with_table("table", table)
.expect("failed to add table")
.build("extern-module-send");
assert!(result.is_ok());
let import = result.unwrap();
let handle = thread::spawn(move || {
let result = ConfigBuilder::new(CommonConfigOptions::default()).build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Statistics::new();
assert!(result.is_ok());
let mut stat = result.unwrap();
let result = Executor::new(Some(&config), Some(&mut stat));
assert!(result.is_ok());
let mut executor = result.unwrap();
let result = Store::new();
assert!(result.is_ok());
let mut store = result.unwrap();
let result = store.register_import_module(&mut executor, &import);
assert!(result.is_ok());
let result = store.module_instance("extern-module-send");
assert!(result.is_some());
let instance = result.unwrap();
assert!(instance.name().is_some());
assert_eq!(instance.name().unwrap(), "extern-module-send");
let result = instance.global("global");
assert!(result.is_some());
let global = result.unwrap();
let result = global.ty();
assert!(result.is_ok());
if let Val::F32(value) = global.get_value() {
assert_eq!(value, 3.5);
}
let result = instance.memory("memory");
assert!(result.is_some());
let mut memory = result.unwrap();
let result = memory.write(vec![1; 10], 10);
assert!(result.is_ok());
let result = memory.read(10, 10);
assert!(result.is_ok());
let data = result.unwrap();
assert_eq!(data, vec![1; 10]);
let result = instance.table("table");
assert!(result.is_some());
let table = result.unwrap();
assert!(table.name().is_some());
assert_eq!(table.name().unwrap(), "table");
assert!(table.mod_name().is_some());
assert_eq!(table.mod_name().unwrap(), "extern-module-send");
assert_eq!(table.size(), 10);
let result = table.ty();
assert!(result.is_ok());
let ty = result.unwrap();
assert_eq!(ty.elem_ty(), RefType::FuncRef);
assert_eq!(ty.minimum(), 10);
assert_eq!(ty.maximum(), Some(20));
let result = instance.func("add");
assert!(result.is_some());
let host_func = result.unwrap();
let result = host_func.ty();
assert!(result.is_ok());
let func_ty = result.unwrap();
assert!(func_ty.args().is_some());
assert_eq!(func_ty.args().unwrap(), [ValType::I32; 2]);
assert!(func_ty.returns().is_some());
assert_eq!(func_ty.returns().unwrap(), [ValType::I32]);
});
handle.join().unwrap();
}
#[test]
#[allow(clippy::assertions_on_result_states)]
fn test_import_sync() {
let result = Global::new(
GlobalType::new(ValType::F32, Mutability::Const),
Val::F32(3.5),
);
assert!(result.is_ok());
let global_const = result.unwrap();
let result = MemoryType::new(10, Some(20), false);
assert!(result.is_ok());
let memory_type = result.unwrap();
let result = Memory::new(memory_type);
assert!(result.is_ok());
let memory = result.unwrap();
let result = Table::new(TableType::new(RefType::FuncRef, 10, Some(20)));
assert!(result.is_ok());
let table = result.unwrap();
let result = ImportObjectBuilder::new()
.with_func::<(i32, i32), i32>("add", real_add)
.expect("failed to add host function")
.with_global("global", global_const)
.expect("failed to add const global")
.with_memory("memory", memory)
.expect("failed to add memory")
.with_table("table", table)
.expect("failed to add table")
.build("extern-module-sync");
assert!(result.is_ok());
let import = result.unwrap();
let import = Arc::new(Mutex::new(import));
let import_cloned = Arc::clone(&import);
let handle = thread::spawn(move || {
let result = import_cloned.lock();
assert!(result.is_ok());
let import = result.unwrap();
let result = ConfigBuilder::new(CommonConfigOptions::default()).build();
assert!(result.is_ok());
let config = result.unwrap();
let result = Statistics::new();
assert!(result.is_ok());
let mut stat = result.unwrap();
let result = Executor::new(Some(&config), Some(&mut stat));
assert!(result.is_ok());
let mut executor = result.unwrap();
let result = Store::new();
assert!(result.is_ok());
let mut store = result.unwrap();
let result = store.register_import_module(&mut executor, &import);
assert!(result.is_ok());
let result = store.module_instance("extern-module-sync");
assert!(result.is_some());
let instance = result.unwrap();
assert!(instance.name().is_some());
assert_eq!(instance.name().unwrap(), "extern-module-sync");
let result = instance.global("global");
assert!(result.is_some());
let global = result.unwrap();
let result = global.ty();
assert!(result.is_ok());
if let Val::F32(v) = global.get_value() {
assert_eq!(v, 3.5);
}
let result = instance.memory("memory");
assert!(result.is_some());
let mut memory = result.unwrap();
let result = memory.write(vec![1; 10], 10);
assert!(result.is_ok());
let result = memory.read(10, 10);
assert!(result.is_ok());
let data = result.unwrap();
assert_eq!(data, vec![1; 10]);
let result = instance.table("table");
assert!(result.is_some());
let table = result.unwrap();
assert!(table.name().is_some());
assert_eq!(table.name().unwrap(), "table");
assert!(table.mod_name().is_some());
assert_eq!(table.mod_name().unwrap(), "extern-module-sync");
assert_eq!(table.size(), 10);
let result = table.ty();
assert!(result.is_ok());
let ty = result.unwrap();
assert_eq!(ty.elem_ty(), RefType::FuncRef);
assert_eq!(ty.minimum(), 10);
assert_eq!(ty.maximum(), Some(20));
let result = instance.func("add");
assert!(result.is_some());
let host_func = result.unwrap();
let result = host_func.ty();
assert!(result.is_ok());
let func_ty = result.unwrap();
assert!(func_ty.args().is_some());
assert_eq!(func_ty.args().unwrap(), [ValType::I32; 2]);
assert!(func_ty.returns().is_some());
assert_eq!(func_ty.returns().unwrap(), [ValType::I32]);
let result = host_func.call(&mut executor, params!(2, 3));
assert!(result.is_ok());
let returns = result.unwrap();
assert_eq!(returns[0].to_i32(), 5);
});
handle.join().unwrap();
}
fn real_add(
_frame: CallingFrame,
inputs: Vec<WasmValue>,
) -> std::result::Result<Vec<WasmValue>, HostFuncError> {
if inputs.len() != 2 {
return Err(HostFuncError::User(1));
}
let a = if inputs[0].ty() == ValType::I32 {
inputs[0].to_i32()
} else {
return Err(HostFuncError::User(2));
};
let b = if inputs[1].ty() == ValType::I32 {
inputs[1].to_i32()
} else {
return Err(HostFuncError::User(3));
};
let c = a + b;
Ok(vec![WasmValue::from_i32(c)])
}
}