Improved JS API a bit further

This commit is contained in:
Syrus Akbary
2022-08-29 19:31:34 +02:00
parent b122feeb83
commit d023c1e7d1
3 changed files with 197 additions and 180 deletions

View File

@@ -227,6 +227,36 @@ impl Imports {
}
}
impl AsJs for Imports {
fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue {
let imports_object = js_sys::Object::new();
for (namespace, name, extern_) in self.iter() {
let val = js_sys::Reflect::get(&imports_object, &namespace.into()).unwrap();
if !val.is_undefined() {
// If the namespace is already set
js_sys::Reflect::set(
&val,
&name.into(),
&extern_.as_jsvalue(&store.as_store_ref()),
)
.unwrap();
} else {
// If the namespace doesn't exist
let import_namespace = js_sys::Object::new();
js_sys::Reflect::set(
&import_namespace,
&name.into(),
&extern_.as_jsvalue(&store.as_store_ref()),
)
.unwrap();
js_sys::Reflect::set(&imports_object, &namespace.into(), &import_namespace.into())
.unwrap();
}
}
imports_object.into()
}
}
pub struct ImportsIterator<'a> {
iter: std::collections::hash_map::Iter<'a, (String, String), Extern>,
}
@@ -363,89 +393,18 @@ macro_rules! import_namespace {
};
}
/*
#[cfg(test)]
mod test {
use crate::js::exports::Exportable;
use crate::js::Type;
use crate::js::{Global, Store, Val};
use crate::js::{Global, Store, Value};
use crate::js::export::Export;
// use wasm_bindgen::*;
use wasm_bindgen_test::*;
fn namespace() {
let mut store = Store::default();
let g1 = Global::new(&store, Val::I32(0));
let namespace = namespace! {
"happy" => g1
};
let imports1 = imports! {
"dog" => namespace
};
let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
assert!(
if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
happy_dog_global.ty.ty == Type::I32
} else {
false
}
);
}
fn imports_macro_allows_trailing_comma_and_none() {
use crate::js::Function;
let mut store = Default::default();
fn func(arg: i32) -> i32 {
arg + 1
}
let _ = imports! {
"env" => {
"func" => Function::new_typed(&store, func),
},
};
let _ = imports! {
"env" => {
"func" => Function::new_typed(&store, func),
}
};
let _ = imports! {
"env" => {
"func" => Function::new_typed(&store, func),
},
"abc" => {
"def" => Function::new_typed(&store, func),
}
};
let _ = imports! {
"env" => {
"func" => Function::new_typed(&store, func)
},
};
let _ = imports! {
"env" => {
"func" => Function::new_typed(&store, func)
}
};
let _ = imports! {
"env" => {
"func1" => Function::new_typed(&store, func),
"func2" => Function::new_typed(&store, func)
}
};
let _ = imports! {
"env" => {
"func1" => Function::new_typed(&store, func),
"func2" => Function::new_typed(&store, func),
}
};
}
#[wasm_bindgen_test]
fn chaining_works() {
let mut store = Store::default();
let g = Global::new(&store, Val::I32(0));
let g = Global::new(&mut store, Value::I32(0));
let mut imports1 = imports! {
"dog" => {
@@ -458,7 +417,7 @@ mod test {
"small" => g.clone()
},
"cat" => {
"small" => g.clone()
"small" => g
}
};
@@ -472,62 +431,162 @@ mod test {
assert!(happy.is_some());
assert!(small.is_some());
}
// fn namespace() {
// let mut store = Store::default();
// let g1 = Global::new(&store, Val::I32(0));
// let namespace = namespace! {
// "happy" => g1
// };
// let imports1 = imports! {
// "dog" => namespace
// };
fn extending_conflict_overwrites() {
let mut store = Store::default();
let g1 = Global::new(&store, Val::I32(0));
let g2 = Global::new(&store, Val::F32(0.));
// let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
let mut imports1 = imports! {
"dog" => {
"happy" => g1,
},
};
// assert!(
// if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
// happy_dog_global.ty.ty == Type::I32
// } else {
// false
// }
// );
// }
let imports2 = imports! {
"dog" => {
"happy" => g2,
},
};
// fn imports_macro_allows_trailing_comma_and_none() {
// use crate::js::Function;
imports1.extend(&imports2);
let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
// let mut store = Default::default();
assert!(
if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
happy_dog_global.ty.ty == Type::F32
} else {
false
// fn func(arg: i32) -> i32 {
// arg + 1
// }
// let _ = imports! {
// "env" => {
// "func" => Function::new_typed(&store, func),
// },
// };
// let _ = imports! {
// "env" => {
// "func" => Function::new_typed(&store, func),
// }
// };
// let _ = imports! {
// "env" => {
// "func" => Function::new_typed(&store, func),
// },
// "abc" => {
// "def" => Function::new_typed(&store, func),
// }
// };
// let _ = imports! {
// "env" => {
// "func" => Function::new_typed(&store, func)
// },
// };
// let _ = imports! {
// "env" => {
// "func" => Function::new_typed(&store, func)
// }
// };
// let _ = imports! {
// "env" => {
// "func1" => Function::new_typed(&store, func),
// "func2" => Function::new_typed(&store, func)
// }
// };
// let _ = imports! {
// "env" => {
// "func1" => Function::new_typed(&store, func),
// "func2" => Function::new_typed(&store, func),
// }
// };
// }
// fn chaining_works() {
// let mut store = Store::default();
// let g = Global::new(&store, Val::I32(0));
// let mut imports1 = imports! {
// "dog" => {
// "happy" => g.clone()
// }
// };
// let imports2 = imports! {
// "dog" => {
// "small" => g.clone()
// },
// "cat" => {
// "small" => g.clone()
// }
// };
// imports1.extend(&imports2);
// let small_cat_export = imports1.get_export("cat", "small");
// assert!(small_cat_export.is_some());
// let happy = imports1.get_export("dog", "happy");
// let small = imports1.get_export("dog", "small");
// assert!(happy.is_some());
// assert!(small.is_some());
// }
// fn extending_conflict_overwrites() {
// let mut store = Store::default();
// let g1 = Global::new(&store, Val::I32(0));
// let g2 = Global::new(&store, Val::F32(0.));
// let mut imports1 = imports! {
// "dog" => {
// "happy" => g1,
// },
// };
// let imports2 = imports! {
// "dog" => {
// "happy" => g2,
// },
// };
// imports1.extend(&imports2);
// let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
// assert!(
// if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
// happy_dog_global.ty.ty == Type::F32
// } else {
// false
// }
// );
// // now test it in reverse
// let mut store = Store::default();
// let g1 = Global::new(&store, Val::I32(0));
// let g2 = Global::new(&store, Val::F32(0.));
// let imports1 = imports! {
// "dog" => {
// "happy" => g1,
// },
// };
// let mut imports2 = imports! {
// "dog" => {
// "happy" => g2,
// },
// };
// imports2.extend(&imports1);
// let happy_dog_entry = imports2.get_export("dog", "happy").unwrap();
// assert!(
// if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
// happy_dog_global.ty.ty == Type::I32
// } else {
// false
// }
// );
// }
}
);
// now test it in reverse
let mut store = Store::default();
let g1 = Global::new(&store, Val::I32(0));
let g2 = Global::new(&store, Val::F32(0.));
let imports1 = imports! {
"dog" => {
"happy" => g1,
},
};
let mut imports2 = imports! {
"dog" => {
"happy" => g2,
},
};
imports2.extend(&imports1);
let happy_dog_entry = imports2.get_export("dog", "happy").unwrap();
assert!(
if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
happy_dog_global.ty.ty == Type::I32
} else {
false
}
);
}
}
*/

View File

@@ -20,8 +20,6 @@ use std::fmt;
pub struct Instance {
_handle: StoreHandle<WebAssembly::Instance>,
module: Module,
#[allow(dead_code)]
imports: Imports,
/// The exports for an instance.
pub exports: Exports,
}
@@ -65,12 +63,11 @@ impl Instance {
module: &Module,
imports: &Imports,
) -> Result<Self, InstantiationError> {
let import_copy = imports.clone();
let (instance, _imports): (StoreHandle<WebAssembly::Instance>, Vec<Extern>) = module
let instance: WebAssembly::Instance = module
.instantiate(&mut store, imports)
.map_err(|e| InstantiationError::Start(e))?;
let self_instance = Self::from_module_and_instance(store, module, instance, import_copy)?;
let self_instance = Self::from_module_and_instance(store, module, instance)?;
//self_instance.init_envs(&imports.iter().map(Extern::to_export).collect::<Vec<_>>())?;
Ok(self_instance)
}
@@ -87,10 +84,9 @@ impl Instance {
pub fn from_module_and_instance(
mut store: &mut impl AsStoreMut,
module: &Module,
instance: StoreHandle<WebAssembly::Instance>,
imports: Imports,
instance: WebAssembly::Instance,
) -> Result<Self, InstantiationError> {
let instance_exports = instance.get(store.as_store_ref().objects()).exports();
let instance_exports = instance.exports();
let exports = module
.exports()
.map(|export_type| {
@@ -109,11 +105,10 @@ impl Instance {
Ok((name.to_string(), extern_))
})
.collect::<Result<Exports, InstantiationError>>()?;
let handle = StoreHandle::new(store.as_store_mut().objects_mut(), instance);
Ok(Self {
_handle: instance,
_handle: handle,
module: module.clone(),
imports,
exports,
})
}

View File

@@ -3,9 +3,8 @@ use crate::js::error::WasmError;
use crate::js::error::{CompileError, InstantiationError};
#[cfg(feature = "js-serializable-module")]
use crate::js::error::{DeserializeError, SerializeError};
use crate::js::externals::Extern;
use crate::js::imports::Imports;
use crate::js::store::{AsStoreMut, StoreHandle};
use crate::js::store::AsStoreMut;
use crate::js::types::{AsJs, ExportType, ImportType};
use crate::js::RuntimeError;
use crate::AsStoreRef;
@@ -222,7 +221,7 @@ impl Module {
&self,
store: &mut impl AsStoreMut,
imports: &Imports,
) -> Result<(StoreHandle<WebAssembly::Instance>, Vec<Extern>), RuntimeError> {
) -> Result<WebAssembly::Instance, RuntimeError> {
// Ensure all imports come from the same store.
if imports
.into_iter()
@@ -232,46 +231,10 @@ impl Module {
InstantiationError::DifferentStores,
)));
}
let imports_object = js_sys::Object::new();
let mut import_externs: Vec<Extern> = vec![];
for import_type in self.imports() {
let resolved_import = imports.get_export(import_type.module(), import_type.name());
if let Some(import) = resolved_import {
let val = js_sys::Reflect::get(&imports_object, &import_type.module().into())?;
if !val.is_undefined() {
// If the namespace is already set
js_sys::Reflect::set(
&val,
&import_type.name().into(),
&import.as_jsvalue(&store.as_store_ref()),
)?;
} else {
// If the namespace doesn't exist
let import_namespace = js_sys::Object::new();
js_sys::Reflect::set(
&import_namespace,
&import_type.name().into(),
&import.as_jsvalue(&store.as_store_ref()),
)?;
js_sys::Reflect::set(
&imports_object,
&import_type.module().into(),
&import_namespace.into(),
)?;
}
import_externs.push(import);
}
// in case the import is not found, the JS Wasm VM will handle
// the error for us, so we don't need to handle it
}
Ok((
StoreHandle::new(
store.as_store_mut().objects_mut(),
WebAssembly::Instance::new(&self.module, &imports_object)
.map_err(|e: JsValue| -> RuntimeError { e.into() })?,
),
import_externs,
))
let imports_js_obj = imports.as_jsvalue(store).into();
Ok(WebAssembly::Instance::new(&self.module, &imports_js_obj)
.map_err(|e: JsValue| -> RuntimeError { e.into() })?)
}
/// Returns the name of the current module.