diff --git a/Cargo.lock b/Cargo.lock index 77909ecd..5e6abe4c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -749,6 +749,18 @@ dependencies = [ "wasm-bindgen-shared", ] +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e8d7523cb1f2a4c96c1317ca690031b714a51cc14e05f712446691f413f5d39" +dependencies = [ + "cfg-if 1.0.0", + "js-sys", + "wasm-bindgen", + "web-sys", +] + [[package]] name = "wasm-bindgen-macro" version = "0.2.78" @@ -907,6 +919,7 @@ version = "0.1.0" dependencies = [ "js-sys", "wasm-bindgen", + "wasm-bindgen-futures", "wasmer", "wasmer-wasi", ] @@ -926,6 +939,16 @@ version = "0.78.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "52144d4c78e5cf8b055ceab8e5fa22814ce4315d6002ad32cfd914f37c12fd65" +[[package]] +name = "web-sys" +version = "0.3.55" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38eb105f1c59d9eaa6b5cdc92b859d85b926e82cb2e0945cd0c9259faa6fe9fb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index 19faf269..6ba49ec5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,5 +10,6 @@ crate-type = ["cdylib"] [dependencies] js-sys = "0.3.55" wasm-bindgen = "0.2.73" +wasm-bindgen-futures = "0.4.28" wasmer = { path = "../wasmer/lib/api", default-features = false, features = ["js-default"] } wasmer-wasi = { path = "../wasmer/lib/wasi", default-features = false, features = ["js"] } diff --git a/src/lib.rs b/src/lib.rs index e28b13fb..bb51a58b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,19 +1,26 @@ use wasm_bindgen::prelude::*; use wasm_bindgen::JsCast; -use wasmer::{ImportObject, Instance, Module, Store}; +use wasmer::{ + ChainableNamedResolver, ImportObject, Instance, JSObjectResolver, Module, NamedResolverChain, +}; use wasmer_wasi::{Stdin, Stdout, WasiEnv, WasiError, WasiState}; +struct InstantiatedWASI { + instance: Instance, + #[allow(dead_code)] + resolver: NamedResolverChain, +} + #[wasm_bindgen] pub struct WASI { wasi_env: WasiEnv, - module: Module, - import_object: ImportObject, + instantiated: Option, } #[wasm_bindgen] impl WASI { #[wasm_bindgen(constructor)] - pub fn new(config: JsValue, module: JsValue) -> Result { + pub fn new(config: JsValue) -> Result { let args: Vec = { let args = js_sys::Reflect::get(&config, &"args".into())?; if args.is_undefined() { @@ -51,53 +58,46 @@ impl WASI { } }; - let mut wasi_env = WasiState::new(&args.get(0).unwrap_or(&"".to_string())) + let wasi_env = WasiState::new(&args.get(0).unwrap_or(&"".to_string())) .args(if args.len() > 0 { &args[1..] } else { &[] }) .envs(env) .finalize() .map_err(|e| js_sys::Error::new(&format!("Failed to create the WasiState: {}`", e)))?; + Ok(WASI { + wasi_env, + instantiated: None, + }) + } + + pub fn instantiate(&mut self, module: JsValue, imports: js_sys::Object) -> Result<(), JsValue> { let module: js_sys::WebAssembly::Module = module.dyn_into().map_err(|_e| { js_sys::Error::new( "You must provide a module to the WASI new. `let module = new WASI({}, module);`", ) })?; let module: Module = module.into(); - let import_object = wasi_env.import_object(&module).map_err(|e| { + let import_object = self.wasi_env.import_object(&module).map_err(|e| { js_sys::Error::new(&format!("Failed to create the Import Object: {}`", e)) })?; - Ok(WASI { - wasi_env, - module, - import_object, - }) - } - - pub async fn instantiate(&mut self, imports: js_sys::Object) -> Result<(), JsValue> { - unimplemented!() - } + let resolver = JSObjectResolver::new(&module, imports); + let resolver = resolver.chain_front(import_object); - #[wasm_bindgen(js_name = getImports)] - pub fn get_imports(&mut self) -> js_sys::Object { - self.import_object.clone().into() + let instance = Instance::new(&module, &resolver) + .map_err(|e| js_sys::Error::new(&format!("Failed to instantiate WASI: {}`", e)))?; + self.instantiated = Some(InstantiatedWASI { resolver, instance }); + Ok(()) } /// Start the WASI Instance, it returns the status code when calling the start /// function - pub fn start(&self, instance: js_sys::WebAssembly::Instance) -> Result { - let instance = Instance::from_module_and_instance(&self.module, instance).map_err(|e| { - js_sys::Error::new(&format!("Error while creating the Wasmer instance: {}", e)) - })?; - let externs = self - .import_object - .clone() - .into_iter() - .map(|((namespace, field), extern_)| extern_) - .collect::>(); - instance.init_envs(&externs); - - let start = instance + pub fn start(&self) -> Result { + let start = self + .instantiated + .as_ref() + .unwrap() + .instance .exports .get_function("_start") .map_err(|_e| js_sys::Error::new("The _start function is not present"))?; @@ -112,9 +112,19 @@ impl WASI { return Ok(exit_code); } Ok(err) => { - unimplemented!(); + return Err(js_sys::Error::new(&format!( + "Unexpected WASI error while running start function: {}", + err + )) + .into()) + } + Err(err) => { + return Err(js_sys::Error::new(&format!( + "Error while running start function: {}", + err + )) + .into()) } - Err(err) => Err(err.into()), } } } diff --git a/tests/index.spec.js b/tests/index.spec.js index 398bd49b..e97075eb 100644 --- a/tests/index.spec.js +++ b/tests/index.spec.js @@ -4,11 +4,10 @@ const { init, WASI } = require('../dist/Library.cjs.js'); async function doWasi(moduleBytes, config) { await init(); + let wasi = new WASI(config); const module = await WebAssembly.compile(moduleBytes); - let wasi = new WASI(config, module); - let imports = wasi.getImports(); - let instance = await WebAssembly.instantiate(module, imports); - wasi.start(instance); + await wasi.instantiate(module, {}); + let code = wasi.start(); return wasi; }