Host exports
Host export
is a function exported from a host and accessible by a Wasm module. Without interface-types it's not so easy to make a convenient API without the necessity for a developer to think about some low-level details (such as memory allocation for passing complex data types).
Marine
makes the development of such functions a trivial task. Each of such functions should be registered in the runtime config with HostImportDescriptor
.
rust
pub type HostExportedFunc = Box<dyn Fn(&mut Ctx, Vec<IValue>) -> Option<IValue> + 'static>;pub struct HostImportDescriptor {/// This closure will be invoked for corresponding import.pub host_exported_func: HostExportedFunc,/// Type of the closure arguments.pub argument_types: Vec<IType>,/// Types of output of the closure.pub output_type: Option<IType>,/// If Some, this closure is called with an error when errors are encountered while lifting./// If None, panic will occur.pub error_handler: Option<Box<dyn Fn(&HostImportError) -> Option<IValue> + 'static>>,}
rust
pub type HostExportedFunc = Box<dyn Fn(&mut Ctx, Vec<IValue>) -> Option<IValue> + 'static>;pub struct HostImportDescriptor {/// This closure will be invoked for corresponding import.pub host_exported_func: HostExportedFunc,/// Type of the closure arguments.pub argument_types: Vec<IType>,/// Types of output of the closure.pub output_type: Option<IType>,/// If Some, this closure is called with an error when errors are encountered while lifting./// If None, panic will occur.pub error_handler: Option<Box<dyn Fn(&HostImportError) -> Option<IValue> + 'static>>,}
And that is how a real-world host exports looks like:
rust
pub(crate) fn create_mounted_binary_import(mounted_binary_path: PathBuf) -> HostImportDescriptor {let host_cmd_closure = move |_ctx: &mut Ctx, raw_args: Vec<IValue>| {let result =mounted_binary_import_impl(&mounted_binary_path, raw_args).unwrap_or_else(Into::into);let raw_result = crate::to_interface_value(&result).unwrap();Some(raw_result)};HostImportDescriptor {host_exported_func: Box::new(host_cmd_closure),argument_types: vec![IType::Array(Box::new(IType::String))],output_type: Some(IType::Record(0)),error_handler: None,}}
rust
pub(crate) fn create_mounted_binary_import(mounted_binary_path: PathBuf) -> HostImportDescriptor {let host_cmd_closure = move |_ctx: &mut Ctx, raw_args: Vec<IValue>| {let result =mounted_binary_import_impl(&mounted_binary_path, raw_args).unwrap_or_else(Into::into);let raw_result = crate::to_interface_value(&result).unwrap();Some(raw_result)};HostImportDescriptor {host_exported_func: Box::new(host_cmd_closure),argument_types: vec![IType::Array(Box::new(IType::String))],output_type: Some(IType::Record(0)),error_handler: None,}}
Take a look at how host_cmd_closure
is defined, it has two arguments: Ctx
could be used for some low-level stuff, while args
represents closure arguments and it's an array of IValue, which could be handled in a handy way then. The result of the closure is Option<IValue>
, and resulted IValue could be easily constructed with a special function to_interface_value
.
And that's it! Just handle arguments, convert the result to IValue, and provide a descriptor!