.. | ||
src | ||
build.rs | ||
Cargo.toml | ||
README.md |
Zed's Plugin Runner
Wasm plugins can be run through wasmtime
, with supported for sandboxed system integration through WASI. There are three plugin
crates that implement different things:
-
plugin_runtime
loads and runs compiledWasm
plugins, and handles setting up system bindings. -
plugin
is the crate that Rust Wasm plugins should depend on. It re-exports some required crates (e.g.serde
,bincode
) and provides some necessary macros for generating bindings thatplugin_runtime
can hook into. -
plugin_macros
implements the proc macros required byplugin
, like the#[bind]
attribute macro.
ABI
The interface between the host Rust runtime ('Runtime') and plugins implemented in Wasm ('Plugin') is pretty simple.
Buffer
is a pair of two 4-byte (u32
) fields, encoded as a single u64
.
struct Buffer {
ptr: u32,
len: u32,
}
All functions that Plugin exports must have the following properties:
-
Have the signature
fn(ptr: u64) -> u64
, where both the argument and return types are aBuffer
:- The input
Buffer
will contain the input arguments serialized tobincode
. - The output
Buffer
will contain the output arguments serialized tobincode
.
- The input
-
Have a name starting with two underscores.
Additionally, Plugin must export an:
__alloc_buffer
function that, given au32
length, returns au32
pointer to a buffer of that length.__free_buffer
function that, given a buffer encoded as au64
, frees the buffer at the given location, and does not return anything.
Note that all of these requirements are automatically fullfilled for any Rust Wasm plugin that uses the plugin
crate, and imports the prelude
.
Here's an example Rust Wasm plugin that doubles the value of every float in a Vec<f64>
passed into it:
use plugin::prelude::*;
#[export]
pub fn double(mut x: Vec<f64>) -> Vec<f64> {
x.into_iter().map(|x| x * 2.0).collect()
}
All the serialization code is automatically generated by #[export]
.
You can specify functions that must be defined host-side by using the #[import]
attribute. This attribute must be attached to a function signature:
#[import]
fn run(command: String) -> Vec<u8>;
The #[import]
macro will generate a function body that performs the proper serialization/deserialization needed to call out to the host rust runtime. Note that the same ABI is used for both #[import]
and #[export]
.