diff --git a/Cargo.lock b/Cargo.lock index d66856c322..68f3132b9a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3717,6 +3717,7 @@ version = "0.1.0" dependencies = [ "anyhow", "bincode", + "pollster", "serde", "serde_json", "wasi-common", diff --git a/crates/plugin_runtime/Cargo.toml b/crates/plugin_runtime/Cargo.toml index b611dfb6a8..492b7e14c9 100644 --- a/crates/plugin_runtime/Cargo.toml +++ b/crates/plugin_runtime/Cargo.toml @@ -11,3 +11,4 @@ anyhow = { version = "1.0", features = ["std"] } serde = "1.0" serde_json = "1.0" bincode = "1.3" +pollster = "0.2.5" \ No newline at end of file diff --git a/crates/plugin_runtime/build.rs b/crates/plugin_runtime/build.rs new file mode 100644 index 0000000000..1cc5b859c6 --- /dev/null +++ b/crates/plugin_runtime/build.rs @@ -0,0 +1,47 @@ +use std::path::Path; + +fn main() { + let base = Path::new("../../plugins"); + + // println!("cargo:rerun-if-changed=../../plugins/*"); + println!("cargo:warning=Rebuilding plugins..."); + + let _ = std::fs::remove_dir_all(base.join("bin")); + let _ = + std::fs::create_dir_all(base.join("bin")).expect("Could not make plugins bin directory"); + + std::process::Command::new("cargo") + .args([ + "build", + "--release", + "--target", + "wasm32-wasi", + "--manifest-path", + base.join("Cargo.toml").to_str().unwrap(), + ]) + .status() + .expect("Could not build plugins"); + + let binaries = std::fs::read_dir(base.join("target/wasm32-wasi/release")) + .expect("Could not find compiled plugins in target"); + println!("cargo:warning={:?}", binaries); + + for file in binaries { + let is_wasm = || { + let path = file.ok()?.path(); + if path.extension()? == "wasm" { + Some(path) + } else { + None + } + }; + + if let Some(path) = is_wasm() { + std::fs::copy(&path, base.join("bin").join(path.file_name().unwrap())) + .expect("Could not copy compiled plugin to bin"); + } + } + + // TODO: create .wat versions + // TODO: optimize with wasm-opt +} diff --git a/crates/plugin_runtime/src/lib.rs b/crates/plugin_runtime/src/lib.rs index 109eb9d4e2..7276edc907 100644 --- a/crates/plugin_runtime/src/lib.rs +++ b/crates/plugin_runtime/src/lib.rs @@ -1,14 +1,56 @@ pub mod wasi; +use pollster::FutureExt as _; pub use wasi::*; -// #[cfg(test)] -// mod tests { -// use super::*; +#[cfg(test)] +mod tests { + use super::*; -// pub fn init_wasi() { -// let plugin = WasiPluginBuilder::new().init(todo!()).unwrap(); -// let handle: WasiFn = plugin.function("hello").unwrap(); -// let result = plugin.call(handle, 27).unwrap(); -// assert_eq!(result, "world 27"); -// } -// } + #[test] + pub fn test_plugin() { + pub struct TestPlugin { + noop: WasiFn<(), ()>, + constant: WasiFn<(), u32>, + identity: WasiFn, + add: WasiFn<(u32, u32), u32>, + swap: WasiFn<(u32, u32), (u32, u32)>, + sort: WasiFn, Vec>, + print: WasiFn, + // and_back: WasiFn, + } + + async { + let mut runtime = WasiPluginBuilder::new_with_default_ctx() + .unwrap() + .host_function("mystery_number", |input: u32| input + 7) + .unwrap() + .init(include_bytes!("../../../plugins/bin/test_plugin.wasm")) + .await + .unwrap(); + + let plugin = TestPlugin { + noop: runtime.function("noop").unwrap(), + constant: runtime.function("constant").unwrap(), + identity: runtime.function("identity").unwrap(), + add: runtime.function("add").unwrap(), + swap: runtime.function("swap").unwrap(), + sort: runtime.function("sort").unwrap(), + print: runtime.function("print").unwrap(), + // and_back: runtime.function("and_back").unwrap(), + }; + + let unsorted = vec![1, 3, 4, 2, 5]; + let sorted = vec![1, 2, 3, 4, 5]; + + assert_eq!(runtime.call(&plugin.noop, ()).await.unwrap(), ()); + assert_eq!(runtime.call(&plugin.constant, ()).await.unwrap(), 27); + assert_eq!(runtime.call(&plugin.identity, 58).await.unwrap(), 58); + assert_eq!(runtime.call(&plugin.add, (3, 4)).await.unwrap(), 7); + assert_eq!(runtime.call(&plugin.swap, (1, 2)).await.unwrap(), (2, 1)); + assert_eq!(runtime.call(&plugin.sort, unsorted).await.unwrap(), sorted); + assert_eq!(runtime.call(&plugin.print, "Hi!".into()).await.unwrap(), ()); + // assert_eq!(runtime.call(&plugin.and_back, 1).await.unwrap(), 8); + } + .block_on() + } +} diff --git a/plugins/Cargo.lock b/plugins/Cargo.lock index 8ef3e49d08..8b6fccd276 100644 --- a/plugins/Cargo.lock +++ b/plugins/Cargo.lock @@ -112,6 +112,13 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "test_plugin" +version = "0.1.0" +dependencies = [ + "plugin", +] + [[package]] name = "unicode-ident" version = "1.0.0" diff --git a/plugins/Cargo.toml b/plugins/Cargo.toml index 7fcc42a745..912ad8eea2 100644 --- a/plugins/Cargo.toml +++ b/plugins/Cargo.toml @@ -1,2 +1,2 @@ [workspace] -members = ["./json_language"] +members = ["./json_language", "./test_plugin"] diff --git a/plugins/test_plugin/Cargo.toml b/plugins/test_plugin/Cargo.toml new file mode 100644 index 0000000000..850b4a7401 --- /dev/null +++ b/plugins/test_plugin/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "test_plugin" +version = "0.1.0" +edition = "2021" + +[dependencies] +plugin = { path = "../../crates/plugin" } + +[lib] +crate-type = ["cdylib"] diff --git a/plugins/test_plugin/src/lib.rs b/plugins/test_plugin/src/lib.rs new file mode 100644 index 0000000000..fcb0a29e22 --- /dev/null +++ b/plugins/test_plugin/src/lib.rs @@ -0,0 +1,44 @@ +use plugin::prelude::*; + +#[export] +pub fn noop() {} + +#[export] +pub fn constant() -> u32 { + 27 +} + +#[export] +pub fn identity(i: u32) -> u32 { + i +} + +#[export] +pub fn add(a: u32, b: u32) -> u32 { + a + b +} + +#[export] +pub fn swap(a: u32, b: u32) -> (u32, u32) { + (b, a) +} + +#[export] +pub fn sort(mut list: Vec) -> Vec { + list.sort(); + list +} + +#[export] +pub fn print(string: String) { + println!("to stdout: {}", string); + eprintln!("to stderr: {}", string); +} + +// #[import] +// fn mystery_number(input: u32) -> u32; + +// #[export] +// pub fn and_back(secret: u32) -> u32 { +// mystery_number(secret) +// }