Fix issue with host function binding

This commit is contained in:
Isaac Clayton 2022-06-09 10:22:53 +02:00
parent 96c2559d2c
commit 7266dff537
2 changed files with 39 additions and 52 deletions

View file

@ -72,59 +72,55 @@ pub struct Wasi {
pub type HostFunction = Box<dyn IntoFunc<WasiCtx, (u32, u32), u32>>; pub type HostFunction = Box<dyn IntoFunc<WasiCtx, (u32, u32), u32>>;
pub struct WasiPluginBuilder { pub struct WasiPluginBuilder {
host_functions: HashMap<String, Box<dyn Fn(&str, &mut Linker<WasiCtx>) -> Result<(), Error>>>, // host_functions: HashMap<String, Box<dyn Fn(&str, &mut Linker<WasiCtx>) -> Result<(), Error>>>,
wasi_ctx_builder: WasiCtxBuilder, wasi_ctx: WasiCtx,
engine: Engine,
linker: Linker<WasiCtx>,
} }
impl WasiPluginBuilder { impl WasiPluginBuilder {
pub fn new() -> Self { pub fn new(wasi_ctx: WasiCtx) -> Result<Self, Error> {
WasiPluginBuilder { let mut config = Config::default();
host_functions: HashMap::new(), config.async_support(true);
wasi_ctx_builder: WasiCtxBuilder::new(), let engine = Engine::new(&config)?;
} let mut linker = Linker::new(&engine);
Ok(WasiPluginBuilder {
// host_functions: HashMap::new(),
wasi_ctx,
engine,
linker,
})
} }
pub fn new_with_default_ctx() -> WasiPluginBuilder { pub fn new_with_default_ctx() -> Result<Self, Error> {
let mut this = Self::new(); let wasi_ctx = WasiCtxBuilder::new()
this.wasi_ctx_builder = this.wasi_ctx_builder.inherit_stdin().inherit_stderr(); .inherit_stdin()
this .inherit_stderr()
.build();
Self::new(wasi_ctx)
} }
pub fn host_function<A: Serialize, R: DeserializeOwned>( pub fn host_function<A: Serialize, R: DeserializeOwned>(
mut self, mut self,
name: &str, name: &str,
function: &dyn Fn(A) -> R + Send + Sync + 'static, function: impl Fn(A) -> R + Send + Sync + 'static,
) -> Self { ) -> Result<Self, Error> {
let name = name.to_string(); self.linker
self.host_functions.insert( .func_wrap("env", name, move |ptr: u32, len: u32| {
name, // TODO: insert serialization code
Box::new(move |name: &str, linker: &mut Linker<WasiCtx>| {
linker.func_wrap("env", name, |ptr: u32, len: u32| {
function(todo!()); function(todo!());
7u32 7u32
})?; })?;
Ok(()) Ok(self)
}),
);
self
}
pub fn wasi_ctx(mut self, config: impl FnOnce(WasiCtxBuilder) -> WasiCtxBuilder) -> Self {
self.wasi_ctx_builder = config(self.wasi_ctx_builder);
self
} }
pub async fn init<T: AsRef<[u8]>>(self, module: T) -> Result<Wasi, Error> { pub async fn init<T: AsRef<[u8]>>(self, module: T) -> Result<Wasi, Error> {
let plugin = WasiPlugin { Wasi::init(module.as_ref().to_vec(), self).await
module: module.as_ref().to_vec(),
wasi_ctx: self.wasi_ctx_builder.build(),
host_functions: self.host_functions,
};
Wasi::init(plugin).await
} }
} }
// TODO: remove
/// Represents a to-be-initialized plugin. /// Represents a to-be-initialized plugin.
/// Please use [`WasiPluginBuilder`], don't use this directly. /// Please use [`WasiPluginBuilder`], don't use this directly.
pub struct WasiPlugin { pub struct WasiPlugin {
@ -154,26 +150,17 @@ impl Wasi {
} }
impl Wasi { impl Wasi {
async fn init(plugin: WasiPlugin) -> Result<Self, Error> { async fn init(module: Vec<u8>, plugin: WasiPluginBuilder) -> Result<Self, Error> {
let mut config = Config::default(); let engine = plugin.engine;
config.async_support(true); let mut linker = plugin.linker;
let engine = Engine::new(&config)?;
let mut linker = Linker::new(&engine);
for (name, add_to_linker) in plugin.host_functions.into_iter() {
add_to_linker(&name, &mut linker)?;
}
linker
.func_wrap("env", "__command", |x: u32, y: u32| x + y)
.unwrap();
linker.func_wrap("env", "__hello", |x: u32| x * 2).unwrap(); linker.func_wrap("env", "__hello", |x: u32| x * 2).unwrap();
linker.func_wrap("env", "__bye", |x: u32| x / 2).unwrap(); linker.func_wrap("env", "__bye", |x: u32| x / 2).unwrap();
wasmtime_wasi::add_to_linker(&mut linker, |s| s)?; wasmtime_wasi::add_to_linker(&mut linker, |s| s)?;
let mut store: Store<_> = Store::new(&engine, plugin.wasi_ctx); let mut store: Store<_> = Store::new(&engine, plugin.wasi_ctx);
let module = Module::new(&engine, plugin.module)?; let module = Module::new(&engine, module)?;
linker.module_async(&mut store, "", &module).await?; linker.module_async(&mut store, "", &module).await?;
let instance = linker.instantiate_async(&mut store, &module).await?; let instance = linker.instantiate_async(&mut store, &module).await?;

View file

@ -13,12 +13,12 @@ use std::{any::Any, path::PathBuf, sync::Arc};
use util::{ResultExt, TryFutureExt}; use util::{ResultExt, TryFutureExt};
pub async fn new_json(executor: Arc<Background>) -> Result<PluginLspAdapter> { pub async fn new_json(executor: Arc<Background>) -> Result<PluginLspAdapter> {
let plugin = WasiPluginBuilder::new_with_default_ctx() let plugin = WasiPluginBuilder::new_with_default_ctx()?
.host_function("command", |command: String| { .host_function("command", |command: String| {
// TODO: actual thing // TODO: actual thing
std::process::Command::new(command).output().unwrap(); std::process::Command::new(command).output().unwrap();
Some("Hello".to_string()) Some("Hello".to_string())
}) })?
.init(include_bytes!("../../../../plugins/bin/json_language.wasm")) .init(include_bytes!("../../../../plugins/bin/json_language.wasm"))
.await?; .await?;
PluginLspAdapter::new(plugin, executor).await PluginLspAdapter::new(plugin, executor).await