From 01bc6ebadcc89b3cd11a7e87a9622e471a8baadd Mon Sep 17 00:00:00 2001 From: Xin Liu Date: Tue, 27 Jun 2023 14:30:05 +0000 Subject: [PATCH] feat(rust-sdk): implement `PluginModuleBuilder` and `PluginModule` Signed-off-by: Xin Liu --- src/externals/function.rs | 2 +- src/externals/table.rs | 2 +- src/import.rs | 43 +++----- src/instance.rs | 2 +- src/lib.rs | 4 +- src/plugin.rs | 205 +++++++++++++++++++++++++++++++++++++- src/store.rs | 4 +- src/vm.rs | 2 +- 8 files changed, 223 insertions(+), 41 deletions(-) diff --git a/src/externals/function.rs b/src/externals/function.rs index 3950645e8..7b351175c 100644 --- a/src/externals/function.rs +++ b/src/externals/function.rs @@ -414,7 +414,7 @@ mod tests { fn test_func_basic() { // create an ImportModule let result = ImportObjectBuilder::::new() - .with_func::<(i32, i32), i32>("add", real_add, None) + .with_func::<(i32, i32), i32>("add", real_add) .expect("failed to add host func") .build("extern"); assert!(result.is_ok()); diff --git a/src/externals/table.rs b/src/externals/table.rs index 095045ab4..923710a0e 100644 --- a/src/externals/table.rs +++ b/src/externals/table.rs @@ -151,7 +151,7 @@ mod tests { // create an import object let result = ImportObjectBuilder::::new() - .with_func::<(i32, i32), i32>("add", real_add, None) + .with_func::<(i32, i32), i32>("add", real_add) .expect("failed to add host func") .with_table("table", table) .build("extern"); diff --git a/src/import.rs b/src/import.rs index 7bf57fdd5..a8a3b0c0f 100644 --- a/src/import.rs +++ b/src/import.rs @@ -1,8 +1,6 @@ #[cfg(all(feature = "async", target_os = "linux"))] use crate::r#async::AsyncHostFn; -use crate::{ - io::WasmValTypeList, Finalizer, FuncType, Global, HostFn, Memory, Table, WasmEdgeResult, -}; +use crate::{io::WasmValTypeList, FuncType, Global, HostFn, Memory, Table, WasmEdgeResult}; use wasmedge_sys::{self as sys, AsImport}; /// Creates a normal or wasi [import object](crate::ImportObject). @@ -64,7 +62,7 @@ use wasmedge_sys::{self as sys, AsImport}; /// let module_name = "extern"; /// let _import = ImportObjectBuilder::::new() /// // add a function -/// .with_func::<(i32, i32), i32>("add", real_add, None)? +/// .with_func::<(i32, i32), i32>("add", real_add)? /// // add a global /// .with_global("global", global_const) /// // add a memory @@ -85,7 +83,6 @@ pub struct ImportObjectBuilder { memories: Vec<(String, sys::Memory)>, tables: Vec<(String, sys::Table)>, host_data: Option>, - finalizer: Option, } impl ImportObjectBuilder { /// Creates a new [ImportObjectBuilder]. @@ -96,7 +93,6 @@ impl ImportObjectBuilder { memories: Vec::new(), tables: Vec::new(), host_data: None, - finalizer: None, } } @@ -110,8 +106,6 @@ impl ImportObjectBuilder { /// /// * `real_func` - The native function. /// - /// * `data` - The additional data object to set to this host function context. - /// /// # error /// /// If fail to create or add the [host function](crate::Func), then an error is returned. @@ -119,7 +113,6 @@ impl ImportObjectBuilder { mut self, name: impl AsRef, real_func: HostFn, - data: Option<&mut T>, ) -> WasmEdgeResult where Args: WasmValTypeList, @@ -128,7 +121,7 @@ impl ImportObjectBuilder { 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(), real_func, data, 0)?; + let inner_func = sys::Function::create::(&ty.into(), real_func, None, 0)?; self.funcs.push((name.as_ref().to_owned(), inner_func)); Ok(self) } @@ -145,8 +138,6 @@ impl ImportObjectBuilder { /// /// * `real_func` - The native function. /// - /// * `data` - The additional data object to set to this host function context. - /// /// # error /// /// If fail to create or add the [host function](crate::Func), then an error is returned. @@ -155,9 +146,8 @@ impl ImportObjectBuilder { name: impl AsRef, ty: FuncType, real_func: HostFn, - data: Option<&mut T>, ) -> WasmEdgeResult { - let inner_func = sys::Function::create::(&ty.into(), real_func, data, 0)?; + let inner_func = sys::Function::create::(&ty.into(), real_func, None, 0)?; self.funcs.push((name.as_ref().to_owned(), inner_func)); Ok(self) } @@ -180,7 +170,6 @@ impl ImportObjectBuilder { mut self, name: impl AsRef, real_func: AsyncHostFn, - ctx_data: Option<&mut T>, ) -> WasmEdgeResult where Args: WasmValTypeList, @@ -189,7 +178,7 @@ impl ImportObjectBuilder { 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(), real_func, ctx_data, 0)?; + let inner_func = sys::Function::create_async(&ty.into(), real_func, None, 0)?; self.funcs.push((name.as_ref().to_owned(), inner_func)); Ok(self) } @@ -239,11 +228,8 @@ impl ImportObjectBuilder { /// /// * `host_data` - The host data to be stored in the module instance. /// - /// * `finalizer` - The function to drop the host data. - /// - pub fn with_host_data(mut self, host_data: Box, finalizer: Option) -> Self { + pub fn with_host_data(mut self, host_data: Box) -> Self { self.host_data = Some(host_data); - self.finalizer = finalizer; self } @@ -257,12 +243,7 @@ impl ImportObjectBuilder { /// /// If fail to create the [ImportObject], then an error is returned. pub fn build(self, name: impl AsRef) -> WasmEdgeResult> { - let mut inner = match self.host_data { - Some(host_data) => { - sys::ImportModule::create_with_data(name.as_ref(), host_data, self.finalizer)? - } - None => sys::ImportModule::create(name.as_ref())?, - }; + let mut inner = sys::ImportModule::create(name.as_ref(), self.host_data)?; // add func for (name, func) in self.funcs.into_iter() { @@ -353,7 +334,7 @@ mod tests { let circle = Box::new(Circle { radius: 10 }); let result = ImportObjectBuilder::::new() - .with_host_data(circle, None) + .with_host_data(circle) .build("extern"); assert!(result.is_ok()); @@ -412,7 +393,7 @@ mod tests { // create an import object let result = ImportObjectBuilder::::new() - .with_func::<(i32, i32), i32>("add", real_add, None) + .with_func::<(i32, i32), i32>("add", real_add) .expect("failed to add host func") .build("extern"); assert!(result.is_ok()); @@ -658,7 +639,7 @@ mod tests { // create an import object let result = ImportObjectBuilder::::new() - .with_func::<(i32, i32), i32>("add", real_add, None) + .with_func::<(i32, i32), i32>("add", real_add) .expect("failed to add host func") .with_table("table", table) .build("extern"); @@ -785,7 +766,7 @@ mod tests { // create an ImportModule instance let result = ImportObjectBuilder::::new() - .with_func::<(i32, i32), i32>("add", real_add, None) + .with_func::<(i32, i32), i32>("add", real_add) .expect("failed to add host function") .with_global("global", global_const) .with_memory("memory", memory) @@ -903,7 +884,7 @@ mod tests { // create an import object let result = ImportObjectBuilder::::new() - .with_func::<(i32, i32), i32>("add", real_add, None) + .with_func::<(i32, i32), i32>("add", real_add) .expect("failed to add host function") .with_global("global", global_const) .with_memory("memory", memory) diff --git a/src/instance.rs b/src/instance.rs index 115745740..96b64a9c5 100644 --- a/src/instance.rs +++ b/src/instance.rs @@ -252,7 +252,7 @@ mod tests { // create an ImportModule instance let result = ImportObjectBuilder::::new() - .with_func::<(i32, i32), i32>("add", real_add, None) + .with_func::<(i32, i32), i32>("add", real_add) .expect("failed to add host function") .with_global("global", global_const) .with_memory("mem", memory) diff --git a/src/lib.rs b/src/lib.rs index 2f729af81..049ae8f58 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -57,7 +57,7 @@ //! { //! // create an import module //! let import = ImportObjectBuilder::::new() -//! .with_func::<(), ()>("say_hello", say_hello, None)? +//! .with_func::<(), ()>("say_hello", say_hello)? //! .build("env")?; //! //! let wasm_bytes = wat2wasm( @@ -165,7 +165,7 @@ pub type CallingFrame = wasmedge_sys::CallingFrame; pub type HostFn = wasmedge_sys::HostFn; -pub type Finalizer = wasmedge_sys::Finalizer; +pub type Finalizer = wasmedge_sys::plugin::Finalizer; #[cfg(all(feature = "async", target_os = "linux"))] pub mod r#async { diff --git a/src/plugin.rs b/src/plugin.rs index 8d13d91e3..5d2d41d07 100644 --- a/src/plugin.rs +++ b/src/plugin.rs @@ -1,7 +1,12 @@ //! Defines plugin related structs. -use crate::{instance::Instance, WasmEdgeResult}; -use wasmedge_sys as sys; +#[cfg(all(feature = "async", target_os = "linux"))] +use crate::r#async::AsyncHostFn; +use crate::{ + instance::Instance, io::WasmValTypeList, Finalizer, FuncType, Global, HostFn, Memory, Table, + WasmEdgeResult, +}; +use wasmedge_sys::{self as sys, AsImport}; pub mod ffi { pub use wasmedge_sys::ffi::{ WasmEdge_ModuleDescriptor, WasmEdge_ModuleInstanceContext, WasmEdge_PluginDescriptor, @@ -211,3 +216,199 @@ impl PluginVersion { } } } + +/// Creates a [plugin module](crate::plugin::PluginModule). +/// +/// # Example +/// +/// [Create a simple math plugin](https://github.com/second-state/wasmedge-rustsdk-examples/tree/main/simple-plugin) +/// +#[derive(Debug, Default)] +pub struct PluginModuleBuilder { + funcs: Vec<(String, sys::Function)>, + globals: Vec<(String, sys::Global)>, + memories: Vec<(String, sys::Memory)>, + tables: Vec<(String, sys::Table)>, + host_data: Option>, + finalizer: Option, +} +impl PluginModuleBuilder { + /// Creates a new [PluginModuleBuilder]. + pub fn new() -> Self { + Self { + funcs: Vec::new(), + globals: Vec::new(), + memories: Vec::new(), + tables: Vec::new(), + host_data: None, + finalizer: None, + } + } + + /// Adds a [host function](crate::Func) to the [PluginModule] to create. + /// + /// N.B. that this function can be used in thread-safe scenarios. + /// + /// # Arguments + /// + /// * `name` - The exported name of the [host function](crate::Func) to add. + /// + /// * `real_func` - The native function. + /// + /// # error + /// + /// If fail to create or add the [host function](crate::Func), then an error is returned. + pub fn with_func( + mut self, + name: impl AsRef, + real_func: HostFn, + ) -> WasmEdgeResult + where + Args: WasmValTypeList, + Rets: WasmValTypeList, + { + 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(), real_func, None, 0)?; + self.funcs.push((name.as_ref().to_owned(), inner_func)); + Ok(self) + } + + /// Adds an [async host function](crate::Func) to the [PluginModule] to create. + /// + /// N.B. that this function can be used in thread-safe scenarios. + /// + /// # Arguments + /// + /// * `name` - The exported name of the [host function](crate::Func) to add. + /// + /// * `real_func` - The native function. + /// + /// # error + /// + /// If fail to create or add the [host function](crate::Func), then an error is returned. + #[cfg(all(feature = "async", target_os = "linux"))] + pub fn with_func_async( + mut self, + name: impl AsRef, + real_func: AsyncHostFn, + ) -> WasmEdgeResult + where + Args: WasmValTypeList, + Rets: WasmValTypeList, + { + 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(), real_func, None, 0)?; + self.funcs.push((name.as_ref().to_owned(), inner_func)); + Ok(self) + } + + /// Adds a [global](crate::Global) to the [PluginModule] to create. + /// + /// # Arguments + /// + /// * `name` - The exported name of the [global](crate::Global) to add. + /// + /// * `global` - The wasm [global instance](crate::Global) to add. + /// + pub fn with_global(mut self, name: impl AsRef, global: Global) -> Self { + self.globals.push((name.as_ref().to_owned(), global.inner)); + self + } + + /// Adds a [memory](crate::Memory) to the [PluginModule] to create. + /// + /// # Arguments + /// + /// * `name` - The exported name of the [memory](crate::Memory) to add. + /// + /// * `memory` - The wasm [memory instance](crate::Memory) to add. + /// + pub fn with_memory(mut self, name: impl AsRef, memory: Memory) -> Self { + self.memories.push((name.as_ref().to_owned(), memory.inner)); + self + } + + /// Adds a [table](crate::Table) to the [PluginModule] to create. + /// + /// # Arguments + /// + /// * `name` - The exported name of the [table](crate::Table) to add. + /// + /// * `table` - The wasm [table instance](crate::Table) to add. + /// + pub fn with_table(mut self, name: impl AsRef, table: Table) -> Self { + self.tables.push((name.as_ref().to_owned(), table.inner)); + self + } + + /// Adds host data to the [PluginModule] to create. + /// + /// # Arguments + /// + /// * `host_data` - The host data to be stored in the module instance. + /// + /// * `finalizer` - The function to drop the host data. Notice that this argument is available only if `host_data` is set some value. + /// + pub fn with_host_data(mut self, host_data: Box, finalizer: Option) -> Self { + self.host_data = Some(host_data); + self.finalizer = finalizer; + self + } + + /// Creates a new [PluginModule]. + /// + /// # Argument + /// + /// * `name` - The name of the [PluginModule] to create. + /// + /// # Error + /// + /// If fail to create the [PluginModule], then an error is returned. + pub fn build(self, name: impl AsRef) -> WasmEdgeResult> { + let mut inner = sys::plugin::PluginModule::create(name.as_ref(), self.host_data, self.finalizer)?; + + // add func + for (name, func) in self.funcs.into_iter() { + inner.add_func(name, func); + } + + // add global + for (name, global) in self.globals.into_iter() { + inner.add_global(name, global); + } + + // add memory + for (name, memory) in self.memories.into_iter() { + inner.add_memory(name, memory); + } + + // add table + for (name, table) in self.tables.into_iter() { + inner.add_table(name, table); + } + + Ok(PluginModule(inner)) + } +} + +/// Defines an import object that contains the required import data used when instantiating a [module](crate::Module). +/// +/// An [PluginModule] instance is created with [PluginModuleBuilder](crate::plugin::PluginModuleBuilder). +#[derive(Debug, Clone)] +pub struct PluginModule(pub(crate) sys::plugin::PluginModule); +impl PluginModule { + /// Returns the name of the plugin module instance. + pub fn name(&self) -> &str { + self.0.name() + } + + /// Returns the raw pointer to the inner `WasmEdge_ModuleInstanceContext`. + #[cfg(feature = "ffi")] + pub fn as_raw_ptr(&self) -> *const sys::ffi::WasmEdge_ModuleInstanceContext { + self.0.as_raw_ptr() + } +} diff --git a/src/store.rs b/src/store.rs index 3a878f4f6..e731c9dd9 100644 --- a/src/store.rs +++ b/src/store.rs @@ -189,7 +189,7 @@ mod tests { // create an ImportModule instance let result = ImportObjectBuilder::::new() - .with_func::<(i32, i32), i32>("add", real_add, None) + .with_func::<(i32, i32), i32>("add", real_add) .expect("failed to add host function") .with_global("global", global_const) .with_memory("mem", memory) @@ -367,7 +367,7 @@ mod tests { // create an ImportModule instance let result = ImportObjectBuilder::::new() - .with_func::<(i32, i32), i32>("add", real_add, None) + .with_func::<(i32, i32), i32>("add", real_add) .expect("failed to add host function") .with_global("global", global_const) .with_memory("mem", memory) diff --git a/src/vm.rs b/src/vm.rs index 0140fa70f..4a4ab1531 100644 --- a/src/vm.rs +++ b/src/vm.rs @@ -1298,7 +1298,7 @@ mod tests { // create an ImportModule instance let result = ImportObjectBuilder::::new() - .with_func::<(i32, i32), i32>("add", real_add, None) + .with_func::<(i32, i32), i32>("add", real_add) .expect("failed to add host function") .with_global("global", global_const) .with_memory("mem", memory)