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_runtimeloads and runs compiledWasmplugins, and handles setting up system bindings. -
pluginis 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_runtimecan hook into. -
plugin_macrosimplements 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
Bufferwill contain the input arguments serialized tobincode. - The output
Bufferwill contain the output arguments serialized tobincode.
- The input
-
Have a name starting with two underscores.
Additionally, Plugin must export an:
__alloc_bufferfunction that, given au32length, returns au32pointer to a buffer of that length.
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].