use std::rc::Rc; use std::collections::HashMap; use std::collections::hash_map::Entry; use elements::{FunctionType, ValueType, GlobalType, MemoryType, TableType}; use interpreter::module::{ExternVal, ModuleInstance}; use interpreter::func::FuncInstance; use interpreter::global::GlobalInstance; use interpreter::memory::MemoryInstance; use interpreter::table::TableInstance; use interpreter::value::RuntimeValue; use interpreter::Error; use interpreter::ImportResolver; pub type HostFunc = Fn(&mut St, &[RuntimeValue]) -> Result, Error>; pub struct HostModuleBuilder { exports: HashMap>, } impl HostModuleBuilder { pub fn new() -> Self { HostModuleBuilder { exports: HashMap::new(), } } pub fn with_func0< Cl: Fn(&mut St) -> Result, Error> + 'static, Ret: AsReturnVal + 'static, N: Into, >( &mut self, name: N, f: Cl, ) { let func_type = FunctionType::new(vec![], Ret::value_type()); let host_func = Rc::new(move |state: &mut St, args: &[RuntimeValue]| -> Result, Error> { let result = f(state); result.map(|r| r.and_then(|r| r.as_return_val())) }); let func = FuncInstance::alloc_host(Rc::new(func_type), host_func); self.insert_func(name, func); } pub fn with_func1< Cl: Fn(&mut St, P1) -> Result, Error> + 'static, Ret: AsReturnVal + 'static, P1: FromArg + 'static, N: Into, >( &mut self, name: N, f: Cl, ) { let func_type = FunctionType::new(vec![P1::value_type()], Ret::value_type()); let host_func = Rc::new(move |state: &mut St, args: &[RuntimeValue]| -> Result, Error> { let arg0 = P1::from_arg(&args[0]); let result = f(state, arg0); result.map(|r| r.and_then(|r| r.as_return_val())) }); let func = FuncInstance::alloc_host(Rc::new(func_type), host_func); self.insert_func(name, func); } pub fn with_func2< Cl: Fn(&mut St, P1, P2) -> Result, Error> + 'static, Ret: AsReturnVal + 'static, P1: FromArg + 'static, P2: FromArg + 'static, N: Into, >( &mut self, name: N, f: Cl, ) { let func_type = FunctionType::new(vec![P1::value_type(), P2::value_type()], Ret::value_type()); let host_func = Rc::new(move |state: &mut St, args: &[RuntimeValue]| -> Result, Error> { let p1 = P1::from_arg(&args[0]); let p2 = P2::from_arg(&args[1]); let result = f(state, p1, p2); result.map(|r| r.and_then(|r| r.as_return_val())) }); let func = FuncInstance::alloc_host(Rc::new(func_type), host_func); self.insert_func(name, func); } pub fn insert_func>(&mut self, name: N, func: Rc>) { self.insert(name, ExternVal::Func(func)); } pub fn insert_global>(&mut self, name: N, global: Rc) { self.insert(name, ExternVal::Global(global)); } pub fn insert_memory>(&mut self, name: N, memory: Rc) { self.insert(name, ExternVal::Memory(memory)); } pub fn insert_table>(&mut self, name: N, table: Rc>) { self.insert(name, ExternVal::Table(table)); } pub fn with_global>(mut self, name: N, global: Rc) -> Self { self.insert_global(name, global); self } pub fn with_memory>(mut self, name: N, memory: Rc) -> Self { self.insert_memory(name, memory); self } pub fn with_table>(mut self, name: N, table: Rc>) -> Self { self.insert_table(name, table); self } fn insert>(&mut self, name: N, extern_val: ExternVal) { match self.exports.entry(name.into()) { Entry::Vacant(v) => v.insert(extern_val), Entry::Occupied(o) => panic!("Duplicate export name {}", o.key()), }; } pub fn build(self) -> HostModule { let internal_instance = Rc::new(ModuleInstance::with_exports(self.exports)); HostModule { internal_instance } } } pub struct HostModule { internal_instance: Rc>, } impl HostModule { pub fn export_by_name(&self, name: &str) -> Option> { self.internal_instance.export_by_name(name) } } impl ImportResolver for HostModule { fn resolve_func( &self, field_name: &str, func_type: &FunctionType, ) -> Result>, Error> { self.internal_instance.resolve_func(field_name, func_type) } fn resolve_global( &self, field_name: &str, global_type: &GlobalType, ) -> Result, Error> { self.internal_instance.resolve_global(field_name, global_type) } fn resolve_memory( &self, field_name: &str, memory_type: &MemoryType, ) -> Result, Error> { self.internal_instance.resolve_memory(field_name, memory_type) } fn resolve_table( &self, field_name: &str, table_type: &TableType, ) -> Result>, Error> { self.internal_instance.resolve_table(field_name, table_type) } } pub trait AnyFunc { fn call_as_any( &self, state: &mut St, args: &[RuntimeValue], ) -> Result, Error>; } pub trait FromArg { fn from_arg(arg: &RuntimeValue) -> Self; fn value_type() -> ValueType; } impl FromArg for i32 { fn from_arg(arg: &RuntimeValue) -> Self { match arg { &RuntimeValue::I32(v) => v, unexpected => panic!("Expected I32, got {:?}", unexpected), } } fn value_type() -> ValueType { ValueType::I32 } } pub trait AsReturnVal { fn as_return_val(self) -> Option; fn value_type() -> Option; } impl AsReturnVal for i32 { fn as_return_val(self) -> Option { Some(self.into()) } fn value_type() -> Option { Some(ValueType::I32) } } impl AsReturnVal for () { fn as_return_val(self) -> Option { None } fn value_type() -> Option { None } } impl AnyFunc for Fn(&mut St) -> Result, Error> { fn call_as_any( &self, state: &mut St, _args: &[RuntimeValue], ) -> Result, Error> { let result = self(state); result.map(|r| r.and_then(|r| r.as_return_val())) } } impl AnyFunc for Fn(&mut St, P1, P2) -> Result, Error> { fn call_as_any( &self, state: &mut St, args: &[RuntimeValue], ) -> Result, Error> { let p1 = P1::from_arg(&args[0]); let p2 = P2::from_arg(&args[1]); let result = self(state, p1, p2); result.map(|r| r.and_then(|r| r.as_return_val())) } }