From d7728213b1638436c98741c39c1caed1139ae7e5 Mon Sep 17 00:00:00 2001 From: geofmureithi Date: Sun, 5 Jan 2025 09:08:49 +0300 Subject: [PATCH 1/4] fix: use msgpack as codec --- Cargo.lock | 47 ++++++++++++++++++++++++++++++--- crates/plugy-core/Cargo.toml | 5 ++-- crates/plugy-core/src/codec.rs | 15 +++++++++++ crates/plugy-core/src/guest.rs | 4 +-- crates/plugy-core/src/lib.rs | 1 + crates/plugy-macros/src/lib.rs | 8 +++--- crates/plugy-runtime/Cargo.toml | 1 - crates/plugy-runtime/src/lib.rs | 11 ++++---- examples/foo-plugin/Cargo.toml | 1 + examples/foo-plugin/src/lib.rs | 7 +++-- examples/runner/Cargo.toml | 1 - 11 files changed, 78 insertions(+), 23 deletions(-) create mode 100644 crates/plugy-core/src/codec.rs diff --git a/Cargo.lock b/Cargo.lock index 0911ce0..30ea7be 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -575,6 +575,7 @@ name = "foo-plugin" version = "0.3.1" dependencies = [ "plugy", + "rmpv", "runner", "serde", ] @@ -1064,6 +1065,15 @@ dependencies = [ "tempfile", ] +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + [[package]] name = "num_cpus" version = "1.16.0" @@ -1218,7 +1228,8 @@ name = "plugy-core" version = "0.3.1" dependencies = [ "anyhow", - "bincode", + "base64", + "rmp-serde", "serde", ] @@ -1239,7 +1250,6 @@ version = "0.3.1" dependencies = [ "anyhow", "async-lock", - "bincode", "dashmap", "plugy", "plugy-core", @@ -1376,13 +1386,44 @@ dependencies = [ "winreg", ] +[[package]] +name = "rmp" +version = "0.8.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "228ed7c16fa39782c3b3468e974aec2795e9089153cd08ee2e9aefb3613334c4" +dependencies = [ + "byteorder", + "num-traits", + "paste", +] + +[[package]] +name = "rmp-serde" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52e599a477cf9840e92f2cde9a7189e67b42c57532749bf90aea6ec10facd4db" +dependencies = [ + "byteorder", + "rmp", + "serde", +] + +[[package]] +name = "rmpv" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "58450723cd9ee93273ce44a20b6ec4efe17f8ed2e3631474387bfdecf18bb2a9" +dependencies = [ + "num-traits", + "rmp", +] + [[package]] name = "runner" version = "0.3.1" dependencies = [ "anyhow", "async-trait", - "bincode", "plugy", "reqwest", "serde", diff --git a/crates/plugy-core/Cargo.toml b/crates/plugy-core/Cargo.toml index 99b9f05..37209fa 100644 --- a/crates/plugy-core/Cargo.toml +++ b/crates/plugy-core/Cargo.toml @@ -13,5 +13,6 @@ repository = "https://github.com/geofmureithi/plugy" [dependencies] serde = { version = "1", features = ["derive"] } -bincode = "1.3.3" -anyhow = "1" \ No newline at end of file +rmp-serde = "1" +anyhow = "1" +base64 = "0.21" diff --git a/crates/plugy-core/src/codec.rs b/crates/plugy-core/src/codec.rs new file mode 100644 index 0000000..4a4abcb --- /dev/null +++ b/crates/plugy-core/src/codec.rs @@ -0,0 +1,15 @@ +/// Deserializes a slice of bytes into an instance of `T`. +pub fn deserialize<'a, T>(bytes: &'a [u8]) -> anyhow::Result +where + T: serde::de::Deserialize<'a>, +{ + Ok(rmp_serde::from_slice(bytes)?) +} + +/// Serializes a serializable object into a `Vec` of bytes. +pub fn serialize(value: &T) -> anyhow::Result> +where + T: serde::Serialize, +{ + Ok(rmp_serde::to_vec(value)?) +} diff --git a/crates/plugy-core/src/guest.rs b/crates/plugy-core/src/guest.rs index 3d23f7e..089faef 100644 --- a/crates/plugy-core/src/guest.rs +++ b/crates/plugy-core/src/guest.rs @@ -113,7 +113,7 @@ pub unsafe extern "C" fn dealloc(value: u64) { /// unsafe { dealloc(combined) }; /// ``` pub fn write_msg(value: &T) -> u64 { - let mut buffer = bincode::serialize(value).expect("could not serialize"); + let mut buffer = crate::codec::serialize(value).expect("could not serialize"); let len = buffer.len(); let ptr = buffer.as_mut_ptr(); std::mem::forget(buffer); @@ -161,5 +161,5 @@ pub unsafe fn read_msg(value: u64) -> T { #[allow(clippy::useless_transmute)] let ptr = std::mem::transmute::(ptr as _); let buffer = Vec::from_raw_parts(ptr, len as _, len as _); - bincode::deserialize(&buffer).expect("invalid bytes provided") + crate::codec::deserialize(&buffer).expect("invalid bytes provided") } diff --git a/crates/plugy-core/src/lib.rs b/crates/plugy-core/src/lib.rs index 0d639a2..5c01d76 100644 --- a/crates/plugy-core/src/lib.rs +++ b/crates/plugy-core/src/lib.rs @@ -14,6 +14,7 @@ use std::{pin::Pin, future::Future}; pub mod bitwise; pub mod guest; +pub mod codec; /// A trait for loading plugin module data asynchronously. /// diff --git a/crates/plugy-macros/src/lib.rs b/crates/plugy-macros/src/lib.rs index 9b3397a..c199d6a 100644 --- a/crates/plugy-macros/src/lib.rs +++ b/crates/plugy-macros/src/lib.rs @@ -207,8 +207,8 @@ pub fn plugin_impl(_metadata: TokenStream, input: TokenStream) -> TokenStream { quote! { #[no_mangle] pub unsafe extern "C" fn #expose_name_ident(value: u64) -> u64 { - let (value, #(#values),*): (#ty, #(#types),*) = plugy::core::guest::read_msg(value); - plugy::core::guest::write_msg(&value.#method_name(#(#values),*)) + let (#(#values),*): (#(#types),*) = plugy::core::guest::read_msg(value); + plugy::core::guest::write_msg(&#ty.#method_name(#(#values),*)) } } }) @@ -342,9 +342,9 @@ pub fn context(args: TokenStream, input: TokenStream) -> TokenStream { .call_async(&mut caller, into_bitwise(ptr, len)) .await .unwrap(); - let (#(#method_pats),*) = bincode::deserialize(&buffer).unwrap(); + let (#(#method_pats),*) = plugy::core::codec::deserialize(&buffer).unwrap(); let buffer = - bincode::serialize(&#struct_name::#method_name(&mut caller, #(#method_pats),*).await) + plugy::core::codec::serialize(&#struct_name::#method_name(&mut caller, #(#method_pats),*).await) .unwrap(); let ptr = alloc_fn .call_async(&mut caller, buffer.len() as _) diff --git a/crates/plugy-runtime/Cargo.toml b/crates/plugy-runtime/Cargo.toml index c6b081b..6a87db7 100644 --- a/crates/plugy-runtime/Cargo.toml +++ b/crates/plugy-runtime/Cargo.toml @@ -13,7 +13,6 @@ repository = "https://github.com/geofmureithi/plugy" [dependencies] anyhow = "1" -bincode = "1.3.3" dashmap = "6.0.0" plugy-core = { path = "../plugy-core", version = "0.3.1" } serde = { version = "1", features = ["derive"] } diff --git a/crates/plugy-runtime/src/lib.rs b/crates/plugy-runtime/src/lib.rs index 5e2d79c..bef7eea 100644 --- a/crates/plugy-runtime/src/lib.rs +++ b/crates/plugy-runtime/src/lib.rs @@ -6,7 +6,6 @@ use anyhow::Context as ErrorContext; use async_lock::RwLock; -use bincode::Error; use dashmap::DashMap; use plugy_core::bitwise::{from_bitwise, into_bitwise}; use plugy_core::PluginLoader; @@ -72,12 +71,12 @@ impl Plugin { self.plugin_type.as_ref() } - pub fn data(&self) -> Result { - bincode::deserialize(&self.data) + pub fn data(&self) -> Result { + plugy_core::codec::deserialize(&self.data) } pub fn update(&mut self, value: &T) { - self.data = bincode::serialize(value).unwrap() + self.data = plugy_core::codec::serialize(value).unwrap() } } @@ -496,7 +495,7 @@ impl Func { memory, alloc_fn, .. } = data; - let buffer = bincode::serialize(value)?; + let buffer = plugy_core::codec::serialize(value)?; let len = buffer.len() as _; let ptr = alloc_fn.call_async(&mut *store, len).await?; memory.write(&mut *store, ptr as _, &buffer)?; @@ -507,7 +506,7 @@ impl Func { let (ptr, len) = from_bitwise(ptr); let mut buffer = vec![0u8; len as _]; memory.read(&mut *store, ptr as _, &mut buffer)?; - Ok(bincode::deserialize(&buffer)?) + Ok(plugy_core::codec::deserialize(&buffer)?) } } diff --git a/examples/foo-plugin/Cargo.toml b/examples/foo-plugin/Cargo.toml index 99753e0..3ee0961 100644 --- a/examples/foo-plugin/Cargo.toml +++ b/examples/foo-plugin/Cargo.toml @@ -12,3 +12,4 @@ crate-type = ["cdylib"] plugy = { path = "../.." } runner = { path = "../../examples/runner" } serde = { version = "1", features = ["derive"] } +rmpv = "1" diff --git a/examples/foo-plugin/src/lib.rs b/examples/foo-plugin/src/lib.rs index 5c8bd42..ca8b772 100644 --- a/examples/foo-plugin/src/lib.rs +++ b/examples/foo-plugin/src/lib.rs @@ -1,14 +1,13 @@ use plugy::macros::plugin_impl; -use serde::Deserialize; -use shared::{Greeter, logger::sync::Logger, fetcher::sync::Fetcher}; +use shared::{fetcher::sync::Fetcher, logger::sync::Logger, Greeter}; -#[derive(Debug, Deserialize)] +#[derive(Debug)] struct FooPlugin; #[plugin_impl] impl Greeter for FooPlugin { fn greet(&self, name: String, last_name: Option) -> String { - let res = Fetcher::fetch("http://example.com".to_owned()); + let res = Fetcher::fetch("https://github.com".to_owned()); Logger::log(&res); let last_name = last_name.unwrap_or_default(); diff --git a/examples/runner/Cargo.toml b/examples/runner/Cargo.toml index 0e94448..c18d975 100644 --- a/examples/runner/Cargo.toml +++ b/examples/runner/Cargo.toml @@ -19,6 +19,5 @@ xtra = { git = "https://github.com/Restioson/xtra", features = ["macros"] } [target.'cfg(not(target_arch = "wasm32"))'.dependencies] tokio = { version = "1", features = ["full"] } plugy = { path = "../../", default-features = false, features = ["runtime"] } -bincode = "1" reqwest = "0.11.18" xtra = { git = "https://github.com/Restioson/xtra", features = ["tokio", "macros"] } From 169ea23fa52a990c8faa2bb4ae75cc27636ba5f3 Mon Sep 17 00:00:00 2001 From: geofmureithi Date: Sun, 5 Jan 2025 09:57:12 +0300 Subject: [PATCH 2/4] fix: remove unnecessary dep --- Cargo.lock | 1 - crates/plugy-core/Cargo.toml | 1 - 2 files changed, 2 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 30ea7be..83fc216 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1228,7 +1228,6 @@ name = "plugy-core" version = "0.3.1" dependencies = [ "anyhow", - "base64", "rmp-serde", "serde", ] diff --git a/crates/plugy-core/Cargo.toml b/crates/plugy-core/Cargo.toml index 37209fa..e1e451d 100644 --- a/crates/plugy-core/Cargo.toml +++ b/crates/plugy-core/Cargo.toml @@ -15,4 +15,3 @@ repository = "https://github.com/geofmureithi/plugy" serde = { version = "1", features = ["derive"] } rmp-serde = "1" anyhow = "1" -base64 = "0.21" From 2111a3fd3f0371e38efa7a5366f8ea5e660ad50c Mon Sep 17 00:00:00 2001 From: geofmureithi Date: Sun, 12 Jan 2025 16:14:39 +0300 Subject: [PATCH 3/4] fix: ease the requirements for plugin loader --- Cargo.lock | 9 --------- crates/plugy-core/src/lib.rs | 13 ++++--------- crates/plugy-macros/src/lib.rs | 2 +- 3 files changed, 5 insertions(+), 19 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index d4c5a52..ff94da7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -104,15 +104,6 @@ version = "0.21.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "604178f6c5c21f02dc555784810edfb88d34ac2c73b2eae109655649ee73ce3d" -[[package]] -name = "bincode" -version = "1.3.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" -dependencies = [ - "serde", -] - [[package]] name = "bitflags" version = "1.3.2" diff --git a/crates/plugy-core/src/lib.rs b/crates/plugy-core/src/lib.rs index 5c01d76..f4a09c7 100644 --- a/crates/plugy-core/src/lib.rs +++ b/crates/plugy-core/src/lib.rs @@ -3,7 +3,7 @@ //! This crate contains fundamental components and utilities that serve as the building blocks for //! plugy's dynamic plugin system. It provides essential functionalities that enable seamless integration //! of plugins into your Rust applications using WebAssembly (Wasm). -//! +//! //! //! ## Modules //! @@ -11,10 +11,10 @@ //! - [`guest`](guest/index.html): A module that facilitates communication between the host application and Wasm plugins. //! -use std::{pin::Pin, future::Future}; +use std::future::Future; pub mod bitwise; -pub mod guest; pub mod codec; +pub mod guest; /// A trait for loading plugin module data asynchronously. /// @@ -28,12 +28,7 @@ pub trait PluginLoader { /// This method returns a `Future` that produces a `Result` containing /// the Wasm module data as a `Vec` on success, or an `anyhow::Error` /// if loading encounters issues. - /// - /// # Returns - /// - /// Returns a `Pin, anyhow::Error>>>>` - /// representing the asynchronous loading process. - fn bytes(&self) -> Pin, anyhow::Error>>>>; + fn bytes(&self) -> impl Future, anyhow::Error>> + Send; /// A plugins name should be known before loading. /// It might just be `std::any::type_name::()` diff --git a/crates/plugy-macros/src/lib.rs b/crates/plugy-macros/src/lib.rs index 2505667..8d93f74 100644 --- a/crates/plugy-macros/src/lib.rs +++ b/crates/plugy-macros/src/lib.rs @@ -233,7 +233,7 @@ pub fn plugin_import(args: TokenStream, input: TokenStream) -> TokenStream { #input impl PluginLoader for #struct_name { - fn bytes(&self) -> std::pin::Pin, anyhow::Error>>>> { + fn bytes(&self) -> std::pin::Pin, anyhow::Error>> + Send + 'static >> { std::boxed::Box::pin(async { let res = std::fs::read(#file_path)?; Ok(res) From a6c32dd055bf17a7d383f0fd4673e69df305a218 Mon Sep 17 00:00:00 2001 From: geofmureithi Date: Sun, 12 Jan 2025 16:30:19 +0300 Subject: [PATCH 4/4] fix: add 'static to Box dyn Plugin --- crates/plugy-macros/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crates/plugy-macros/src/lib.rs b/crates/plugy-macros/src/lib.rs index 8d93f74..283824d 100644 --- a/crates/plugy-macros/src/lib.rs +++ b/crates/plugy-macros/src/lib.rs @@ -125,7 +125,7 @@ fn generate_async_trait(trait_item: &ItemTrait) -> proc_macro2::TokenStream { #(#async_methods)* } #[cfg(not(target_arch = "wasm32"))] - impl plugy::runtime::IntoCallable for Box> { + impl plugy::runtime::IntoCallable for Box + 'static> { type Output = #callable_trait_ident; fn into_callable(handle: plugy::runtime::PluginHandle>) -> Self::Output { #callable_trait_ident { handle, inner: std::marker::PhantomData }