mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-07 21:28:21 +00:00
api/js: Replace ImportObject with new type Imports
This commit is contained in:
@@ -192,32 +192,6 @@ impl Exports {
|
||||
iter: self.map.iter(),
|
||||
}
|
||||
}
|
||||
|
||||
/// safa
|
||||
pub fn get_namespace_export(&self, name: &str) -> Option<Export> {
|
||||
self.map.get(name).map(|is_export| is_export.to_export())
|
||||
}
|
||||
|
||||
/// safa
|
||||
pub fn get_namespace_externs(&self) -> Vec<(String, Extern)> {
|
||||
self.map
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.clone()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// safa
|
||||
pub fn get_namespace_exports(&self) -> Vec<(String, Export)> {
|
||||
self.map
|
||||
.iter()
|
||||
.map(|(k, v)| (k.clone(), v.to_export()))
|
||||
.collect()
|
||||
}
|
||||
|
||||
/// safa
|
||||
pub fn as_exports(&self) -> Option<Exports> {
|
||||
Some(self.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Exports {
|
||||
@@ -300,20 +274,20 @@ impl FromIterator<(String, Extern)> for Exports {
|
||||
}
|
||||
|
||||
impl IntoIterator for Exports {
|
||||
type IntoIter = std::vec::IntoIter<(String, Extern)>;
|
||||
type IntoIter = indexmap::map::IntoIter<String, Extern>;
|
||||
type Item = (String, Extern);
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.get_namespace_externs().into_iter()
|
||||
self.map.clone().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for &Exports {
|
||||
type IntoIter = std::vec::IntoIter<(String, Extern)>;
|
||||
type Item = (String, Extern);
|
||||
impl<'a> IntoIterator for &'a Exports {
|
||||
type IntoIter = indexmap::map::Iter<'a, String, Extern>;
|
||||
type Item = (&'a String, &'a Extern);
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.get_namespace_externs().into_iter()
|
||||
self.map.iter()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -2,11 +2,11 @@
|
||||
//! manipulate and access a wasm module's imports including memories, tables, globals, and
|
||||
//! functions.
|
||||
use crate::js::export::Export;
|
||||
use crate::js::exports::Exportable;
|
||||
use crate::js::resolver::NamedResolver;
|
||||
use crate::js::exports::{Exportable, Exports};
|
||||
use crate::js::instance::InstantiationError;
|
||||
use crate::js::module::Module;
|
||||
use crate::Extern;
|
||||
use std::borrow::{Borrow, BorrowMut};
|
||||
use std::collections::{hash_map::Entry, HashMap};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
|
||||
/// All of the import data used when instantiating.
|
||||
@@ -17,18 +17,24 @@ use std::fmt;
|
||||
/// [`imports!`]: macro.imports.html
|
||||
///
|
||||
/// # Usage:
|
||||
/// ```ignore
|
||||
/// use wasmer::{Exports, Imports, Function};
|
||||
/// ```no_run
|
||||
/// use wasmer::{Exports, Module, Store, Instance, imports, Imports, Function};
|
||||
/// # fn foo_test(module: Module, store: Store) {
|
||||
///
|
||||
/// let mut import_object = Imports::new();
|
||||
/// let mut env = Exports::new();
|
||||
/// let host_fn = Function::new_native(foo);
|
||||
/// let import_object: Imports = imports! {
|
||||
/// "env" => {
|
||||
/// "foo" => host_fn,
|
||||
/// },
|
||||
/// };
|
||||
///
|
||||
/// env.insert("foo", Function::new_native(foo));
|
||||
/// import_object.register("env", env);
|
||||
/// let instance = Instance::new(&module, &import_object).expect("Could not instantiate module.");
|
||||
///
|
||||
/// fn foo(n: i32) -> i32 {
|
||||
/// n
|
||||
/// }
|
||||
///
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Imports {
|
||||
@@ -44,15 +50,15 @@ impl Imports {
|
||||
/// Gets an export given a ns and a name
|
||||
///
|
||||
/// # Usage
|
||||
/// ```ignore
|
||||
/// # use wasmer::{Imports, Instance, Namespace};
|
||||
/// ```no_run
|
||||
/// # use wasmer::Imports;
|
||||
/// let mut import_object = Imports::new();
|
||||
/// import_object.get_export("ns", "name");
|
||||
/// ```
|
||||
pub fn get_export(&self, ns: &str, name: &str) -> Option<Export> {
|
||||
pub fn get_export(&self, ns: &str, name: &str) -> Option<Extern> {
|
||||
if self.map.contains_key(&(ns.to_string(), name.to_string())) {
|
||||
let ext = &self.map[&(ns.to_string(), name.to_string())];
|
||||
return Some(ext.to_export());
|
||||
return Some(ext.clone());
|
||||
}
|
||||
None
|
||||
}
|
||||
@@ -62,7 +68,20 @@ impl Imports {
|
||||
self.map.keys().any(|(k, _)| (k == name))
|
||||
}
|
||||
|
||||
/// TODO: Add doc
|
||||
/// Register a list of externs into a namespace.
|
||||
///
|
||||
/// # Usage:
|
||||
/// ```no_run
|
||||
/// # use wasmer::{Imports, Exports, Memory};
|
||||
/// # fn foo_test(memory: Memory) {
|
||||
/// let mut exports = Exports::new()
|
||||
/// exports.insert("memory", memory);
|
||||
///
|
||||
/// let mut import_object = Imports::new();
|
||||
/// import_object.register_namespace("env", exports);
|
||||
/// // ...
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn register_namespace(
|
||||
&mut self,
|
||||
ns: &str,
|
||||
@@ -73,47 +92,62 @@ impl Imports {
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO: Add doc
|
||||
pub fn define(&mut self, ns: &str, name: &str, extern_: Extern) {
|
||||
self.map.insert((ns.to_string(), name.to_string()), extern_);
|
||||
/// Add a single import with a namespace `ns` and name `name`.
|
||||
///
|
||||
/// # Usage
|
||||
/// ```no_run
|
||||
/// # let store = Default::default();
|
||||
/// use wasmer::{Imports, Function};
|
||||
/// fn foo(n: i32) -> i32 {
|
||||
/// n
|
||||
/// }
|
||||
/// let mut import_object = Imports::new();
|
||||
/// import_object.define("env", "foo", Function::new_native(foo));
|
||||
/// ```
|
||||
pub fn define(&mut self, ns: &str, name: &str, val: impl Into<Extern>) {
|
||||
self.map
|
||||
.insert((ns.to_string(), name.to_string()), val.into());
|
||||
}
|
||||
|
||||
// /// Register anything that implements `LikeNamespace` as a namespace.
|
||||
// ///
|
||||
// /// # Usage:
|
||||
// /// ```ignore
|
||||
// /// # use wasmer::{Imports, Instance, Namespace};
|
||||
// /// let mut import_object = Imports::new();
|
||||
// ///
|
||||
// /// import_object.register("namespace0", instance);
|
||||
// /// import_object.register("namespace1", namespace);
|
||||
// /// // ...
|
||||
// /// ```
|
||||
// pub fn register<S, N>(&mut self, name: S, namespace: N) -> Option<Box<dyn LikeNamespace>>
|
||||
// where
|
||||
// S: Into<String>,
|
||||
// N: LikeNamespace + Send + Sync + 'static,
|
||||
// {
|
||||
// let mut guard = self.map.lock().unwrap();
|
||||
// let map = guard.borrow_mut();
|
||||
|
||||
// match map.entry(name.into()) {
|
||||
// Entry::Vacant(empty) => {
|
||||
// empty.insert(Box::new(namespace));
|
||||
// None
|
||||
// }
|
||||
// Entry::Occupied(mut occupied) => Some(occupied.insert(Box::new(namespace))),
|
||||
// }
|
||||
// }
|
||||
|
||||
/// asdfsa
|
||||
pub fn resolve_by_name(&self, ns: &str, name: &str) -> Option<Export> {
|
||||
self.get_export(ns, name)
|
||||
/// Returns the contents of a namespace as an `Exports`.
|
||||
///
|
||||
/// Returns `None` if the namespace doesn't exist.
|
||||
pub fn get_namespace_exports(&self, name: &str) -> Option<Exports> {
|
||||
let ret: Exports = self
|
||||
.map
|
||||
.iter()
|
||||
.filter(|((ns, _), _)| ns == name)
|
||||
.map(|((_, name), e)| (name.clone(), e.clone()))
|
||||
.collect();
|
||||
if ret.is_empty() {
|
||||
None
|
||||
} else {
|
||||
Some(ret)
|
||||
}
|
||||
}
|
||||
|
||||
//fn iter(&self) -> impl Iterator<(&str, &str, Extern)> {
|
||||
// todo!()
|
||||
//}
|
||||
/// Resolve and return a vector of imports in the order they are defined in the `module`'s source code.
|
||||
///
|
||||
/// This means the returned `Vec<Extern>` might be a subset of the imports contained in `self`.
|
||||
pub fn imports_for_module(&self, module: &Module) -> Result<Vec<Extern>, InstantiationError> {
|
||||
let mut ret = vec![];
|
||||
for import in module.imports() {
|
||||
if let Some(imp) = self
|
||||
.map
|
||||
.get(&(import.module().to_string(), import.name().to_string()))
|
||||
{
|
||||
ret.push(imp.clone());
|
||||
} else {
|
||||
return Err(InstantiationError::Link(format!(
|
||||
"Error while importing {0:?}.{1:?}: unknown import. Expected {2:?}",
|
||||
import.module(),
|
||||
import.name(),
|
||||
import.ty()
|
||||
)));
|
||||
}
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Returns the `Imports` as a Javascript `Object`
|
||||
pub fn as_jsobject(&self) -> js_sys::Object {
|
||||
@@ -151,12 +185,6 @@ impl Into<js_sys::Object> for Imports {
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedResolver for Imports {
|
||||
fn resolve_by_name(&self, ns: &str, name: &str) -> Option<Export> {
|
||||
self.get_export(ns, name)
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for &Imports {
|
||||
type IntoIter = std::collections::hash_map::IntoIter<(String, String), Extern>;
|
||||
type Item = ((String, String), Extern);
|
||||
@@ -166,6 +194,14 @@ impl IntoIterator for &Imports {
|
||||
}
|
||||
}
|
||||
|
||||
impl Extend<((String, String), Extern)> for Imports {
|
||||
fn extend<T: IntoIterator<Item = ((String, String), Extern)>>(&mut self, iter: T) {
|
||||
for ((ns, name), ext) in iter.into_iter() {
|
||||
self.define(&ns, &name, ext);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Imports {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
enum SecretMap {
|
||||
@@ -267,96 +303,11 @@ macro_rules! import_namespace {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use super::*;
|
||||
use crate::js::ChainableNamedResolver;
|
||||
use crate::js::exports::Exportable;
|
||||
use crate::js::Type;
|
||||
use crate::js::{Global, Store, Val};
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn chaining_works() {
|
||||
let store = Store::default();
|
||||
let g = Global::new(&store, Val::I32(0));
|
||||
|
||||
let imports1 = imports! {
|
||||
"dog" => {
|
||||
"happy" => g.clone()
|
||||
}
|
||||
};
|
||||
|
||||
let imports2 = imports! {
|
||||
"dog" => {
|
||||
"small" => g.clone()
|
||||
},
|
||||
"cat" => {
|
||||
"small" => g.clone()
|
||||
}
|
||||
};
|
||||
|
||||
let resolver = imports1.chain_front(imports2);
|
||||
|
||||
let small_cat_export = resolver.resolve_by_name("cat", "small");
|
||||
assert!(small_cat_export.is_some());
|
||||
|
||||
let happy = resolver.resolve_by_name("dog", "happy");
|
||||
let small = resolver.resolve_by_name("dog", "small");
|
||||
assert!(happy.is_some());
|
||||
assert!(small.is_some());
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn extending_conflict_overwrites() {
|
||||
let 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 imports2 = imports! {
|
||||
"dog" => {
|
||||
"happy" => g2,
|
||||
},
|
||||
};
|
||||
|
||||
let resolver = imports1.chain_front(imports2);
|
||||
let happy_dog_entry = resolver.resolve_by_name("dog", "happy").unwrap();
|
||||
|
||||
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
|
||||
happy_dog_global.ty.ty == Type::F32
|
||||
} else {
|
||||
false
|
||||
});
|
||||
|
||||
// now test it in reverse
|
||||
let 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 imports2 = imports! {
|
||||
"dog" => {
|
||||
"happy" => g2,
|
||||
},
|
||||
};
|
||||
|
||||
let resolver = imports1.chain_back(imports2);
|
||||
let happy_dog_entry = resolver.resolve_by_name("dog", "happy").unwrap();
|
||||
|
||||
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
|
||||
happy_dog_global.ty.ty == Type::I32
|
||||
} else {
|
||||
false
|
||||
});
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn namespace() {
|
||||
let store = Store::default();
|
||||
@@ -368,13 +319,15 @@ mod test {
|
||||
"dog" => namespace
|
||||
};
|
||||
|
||||
let happy_dog_entry = imports1.resolve_by_name("dog", "happy").unwrap();
|
||||
let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
|
||||
|
||||
assert!(if let Export::Global(happy_dog_global) = happy_dog_entry {
|
||||
happy_dog_global.ty.ty == Type::I32
|
||||
} else {
|
||||
false
|
||||
});
|
||||
assert!(
|
||||
if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
||||
happy_dog_global.ty.ty == Type::I32
|
||||
} else {
|
||||
false
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
@@ -428,4 +381,93 @@ mod test {
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn chaining_works() {
|
||||
let 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());
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn extending_conflict_overwrites() {
|
||||
let 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 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
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use crate::js::env::HostEnvInitError;
|
||||
use crate::js::export::Export;
|
||||
use crate::js::exports::Exports;
|
||||
use crate::js::exports::{Exportable, Exports};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::imports::Imports;
|
||||
use crate::js::module::Module;
|
||||
use crate::js::resolver::Resolver;
|
||||
use crate::js::store::Store;
|
||||
use crate::js::trap::RuntimeError;
|
||||
use js_sys::WebAssembly;
|
||||
@@ -23,6 +23,8 @@ use thiserror::Error;
|
||||
pub struct Instance {
|
||||
instance: WebAssembly::Instance,
|
||||
module: Module,
|
||||
#[allow(dead_code)]
|
||||
imports: Imports,
|
||||
/// The exports for an instance.
|
||||
pub exports: Exports,
|
||||
}
|
||||
@@ -92,16 +94,14 @@ impl Instance {
|
||||
/// Those are, as defined by the spec:
|
||||
/// * Link errors that happen when plugging the imports into the instance
|
||||
/// * Runtime errors that happen when running the module `start` function.
|
||||
pub fn new(
|
||||
module: &Module,
|
||||
resolver: &(dyn Resolver + Send + Sync),
|
||||
) -> Result<Self, InstantiationError> {
|
||||
let (instance, imports) = module
|
||||
.instantiate(resolver)
|
||||
pub fn new(module: &Module, imports: &Imports) -> Result<Self, InstantiationError> {
|
||||
let import_copy = imports.clone();
|
||||
let (instance, imports): (WebAssembly::Instance, Vec<Extern>) = module
|
||||
.instantiate(imports)
|
||||
.map_err(|e| InstantiationError::Start(e))?;
|
||||
|
||||
let self_instance = Self::from_module_and_instance(module, instance)?;
|
||||
self_instance.init_envs(&imports)?;
|
||||
let self_instance = Self::from_module_and_instance(module, instance, import_copy)?;
|
||||
self_instance.init_envs(&imports.iter().map(Extern::to_export).collect::<Vec<_>>())?;
|
||||
Ok(self_instance)
|
||||
}
|
||||
|
||||
@@ -117,6 +117,7 @@ impl Instance {
|
||||
pub fn from_module_and_instance(
|
||||
module: &Module,
|
||||
instance: WebAssembly::Instance,
|
||||
imports: Imports,
|
||||
) -> Result<Self, InstantiationError> {
|
||||
let store = module.store();
|
||||
let instance_exports = instance.exports();
|
||||
@@ -141,6 +142,7 @@ impl Instance {
|
||||
Ok(Self {
|
||||
instance,
|
||||
module: module.clone(),
|
||||
imports,
|
||||
exports,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
use crate::js::{Export, ExternType, Module, NamedResolver};
|
||||
use crate::js::{Export, ExternType, Module};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// This struct is used in case you want to create an `Instance`
|
||||
@@ -67,9 +67,3 @@ impl Into<js_sys::Object> for JsImportObject {
|
||||
self.object
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedResolver for JsImportObject {
|
||||
fn resolve_by_name(&self, module: &str, name: &str) -> Option<Export> {
|
||||
self.get_export(module, name)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,6 @@ mod module;
|
||||
mod module_info_polyfill;
|
||||
mod native;
|
||||
mod ptr;
|
||||
mod resolver;
|
||||
mod store;
|
||||
mod trap;
|
||||
mod types;
|
||||
@@ -63,9 +62,6 @@ pub use crate::js::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSlice
|
||||
pub use crate::js::module::{Module, ModuleTypeHints};
|
||||
pub use crate::js::native::NativeFunc;
|
||||
pub use crate::js::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64};
|
||||
pub use crate::js::resolver::{
|
||||
ChainableNamedResolver, NamedResolver, NamedResolverChain, Resolver,
|
||||
};
|
||||
pub use crate::js::trap::RuntimeError;
|
||||
|
||||
pub use crate::js::store::{Store, StoreObject};
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
use crate::js::export::Export;
|
||||
use crate::js::resolver::Resolver;
|
||||
use crate::js::exports::Exportable;
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::imports::Imports;
|
||||
use crate::js::store::Store;
|
||||
use crate::js::types::{ExportType, ImportType};
|
||||
// use crate::js::InstantiationError;
|
||||
@@ -217,28 +218,31 @@ impl Module {
|
||||
|
||||
pub(crate) fn instantiate(
|
||||
&self,
|
||||
resolver: &dyn Resolver,
|
||||
) -> Result<(WebAssembly::Instance, Vec<Export>), RuntimeError> {
|
||||
let imports = js_sys::Object::new();
|
||||
let mut import_externs: Vec<Export> = vec![];
|
||||
for (i, import_type) in self.imports().enumerate() {
|
||||
let resolved_import =
|
||||
resolver.resolve(i as u32, import_type.module(), import_type.name());
|
||||
imports: &Imports,
|
||||
) -> Result<(WebAssembly::Instance, Vec<Extern>), RuntimeError> {
|
||||
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, &import_type.module().into())?;
|
||||
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())?;
|
||||
js_sys::Reflect::set(
|
||||
&val,
|
||||
&import_type.name().into(),
|
||||
import.to_export().as_jsvalue(),
|
||||
)?;
|
||||
} 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(),
|
||||
import.to_export().as_jsvalue(),
|
||||
)?;
|
||||
js_sys::Reflect::set(
|
||||
&imports,
|
||||
&imports_object,
|
||||
&import_type.module().into(),
|
||||
&import_namespace.into(),
|
||||
)?;
|
||||
@@ -249,7 +253,7 @@ impl Module {
|
||||
// the error for us, so we don't need to handle it
|
||||
}
|
||||
Ok((
|
||||
WebAssembly::Instance::new(&self.module, &imports)
|
||||
WebAssembly::Instance::new(&self.module, &imports_object)
|
||||
.map_err(|e: JsValue| -> RuntimeError { e.into() })?,
|
||||
import_externs,
|
||||
))
|
||||
|
||||
@@ -1,165 +0,0 @@
|
||||
use crate::js::export::Export;
|
||||
|
||||
/// Import resolver connects imports with available exported values.
|
||||
pub trait Resolver {
|
||||
/// Resolves an import a WebAssembly module to an export it's hooked up to.
|
||||
///
|
||||
/// The `index` provided is the index of the import in the wasm module
|
||||
/// that's being resolved. For example 1 means that it's the second import
|
||||
/// listed in the wasm module.
|
||||
///
|
||||
/// The `module` and `field` arguments provided are the module/field names
|
||||
/// listed on the import itself.
|
||||
///
|
||||
/// # Notes:
|
||||
///
|
||||
/// The index is useful because some WebAssembly modules may rely on that
|
||||
/// for resolving ambiguity in their imports. Such as:
|
||||
/// ```ignore
|
||||
/// (module
|
||||
/// (import "" "" (func))
|
||||
/// (import "" "" (func (param i32) (result i32)))
|
||||
/// )
|
||||
/// ```
|
||||
fn resolve(&self, _index: u32, module: &str, field: &str) -> Option<Export>;
|
||||
}
|
||||
|
||||
/// Import resolver connects imports with available exported values.
|
||||
///
|
||||
/// This is a specific subtrait for [`Resolver`] for those users who don't
|
||||
/// care about the `index`, but only about the `module` and `field` for
|
||||
/// the resolution.
|
||||
pub trait NamedResolver {
|
||||
/// Resolves an import a WebAssembly module to an export it's hooked up to.
|
||||
///
|
||||
/// It receives the `module` and `field` names and return the [`Export`] in
|
||||
/// case it's found.
|
||||
fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export>;
|
||||
}
|
||||
|
||||
// All NamedResolvers should extend `Resolver`.
|
||||
impl<T: NamedResolver> Resolver for T {
|
||||
/// By default this method will be calling [`NamedResolver::resolve_by_name`],
|
||||
/// dismissing the provided `index`.
|
||||
fn resolve(&self, _index: u32, module: &str, field: &str) -> Option<Export> {
|
||||
self.resolve_by_name(module, field)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: NamedResolver> NamedResolver for &T {
|
||||
fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export> {
|
||||
(**self).resolve_by_name(module, field)
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedResolver for Box<dyn NamedResolver + Send + Sync> {
|
||||
fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export> {
|
||||
(**self).resolve_by_name(module, field)
|
||||
}
|
||||
}
|
||||
|
||||
impl NamedResolver for () {
|
||||
/// Always returns `None`.
|
||||
fn resolve_by_name(&self, _module: &str, _field: &str) -> Option<Export> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// `Resolver` implementation that always resolves to `None`. Equivalent to `()`.
|
||||
pub struct NullResolver {}
|
||||
|
||||
impl Resolver for NullResolver {
|
||||
fn resolve(&self, _idx: u32, _module: &str, _field: &str) -> Option<Export> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
/// A [`Resolver`] that links two resolvers together in a chain.
|
||||
pub struct NamedResolverChain<A: NamedResolver + Send + Sync, B: NamedResolver + Send + Sync> {
|
||||
a: A,
|
||||
b: B,
|
||||
}
|
||||
|
||||
/// A trait for chaining resolvers together.
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer_engine::{ChainableNamedResolver, NamedResolver};
|
||||
/// # fn chainable_test<A, B>(imports1: A, imports2: B)
|
||||
/// # where A: NamedResolver + Sized + Send + Sync,
|
||||
/// # B: NamedResolver + Sized + Send + Sync,
|
||||
/// # {
|
||||
/// // override duplicates with imports from `imports2`
|
||||
/// imports1.chain_front(imports2);
|
||||
/// # }
|
||||
/// ```
|
||||
pub trait ChainableNamedResolver: NamedResolver + Sized + Send + Sync {
|
||||
/// Chain a resolver in front of the current resolver.
|
||||
///
|
||||
/// This will cause the second resolver to override the first.
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer_engine::{ChainableNamedResolver, NamedResolver};
|
||||
/// # fn chainable_test<A, B>(imports1: A, imports2: B)
|
||||
/// # where A: NamedResolver + Sized + Send + Sync,
|
||||
/// # B: NamedResolver + Sized + Send + Sync,
|
||||
/// # {
|
||||
/// // override duplicates with imports from `imports2`
|
||||
/// imports1.chain_front(imports2);
|
||||
/// # }
|
||||
/// ```
|
||||
fn chain_front<U>(self, other: U) -> NamedResolverChain<U, Self>
|
||||
where
|
||||
U: NamedResolver + Send + Sync,
|
||||
{
|
||||
NamedResolverChain { a: other, b: self }
|
||||
}
|
||||
|
||||
/// Chain a resolver behind the current resolver.
|
||||
///
|
||||
/// This will cause the first resolver to override the second.
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer_engine::{ChainableNamedResolver, NamedResolver};
|
||||
/// # fn chainable_test<A, B>(imports1: A, imports2: B)
|
||||
/// # where A: NamedResolver + Sized + Send + Sync,
|
||||
/// # B: NamedResolver + Sized + Send + Sync,
|
||||
/// # {
|
||||
/// // override duplicates with imports from `imports1`
|
||||
/// imports1.chain_back(imports2);
|
||||
/// # }
|
||||
/// ```
|
||||
fn chain_back<U>(self, other: U) -> NamedResolverChain<Self, U>
|
||||
where
|
||||
U: NamedResolver + Send + Sync,
|
||||
{
|
||||
NamedResolverChain { a: self, b: other }
|
||||
}
|
||||
}
|
||||
|
||||
// We give these chain methods to all types implementing NamedResolver
|
||||
impl<T: NamedResolver + Send + Sync> ChainableNamedResolver for T {}
|
||||
|
||||
impl<A, B> NamedResolver for NamedResolverChain<A, B>
|
||||
where
|
||||
A: NamedResolver + Send + Sync,
|
||||
B: NamedResolver + Send + Sync,
|
||||
{
|
||||
fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export> {
|
||||
self.a
|
||||
.resolve_by_name(module, field)
|
||||
.or_else(|| self.b.resolve_by_name(module, field))
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, B> Clone for NamedResolverChain<A, B>
|
||||
where
|
||||
A: NamedResolver + Clone + Send + Sync,
|
||||
B: NamedResolver + Clone + Send + Sync,
|
||||
{
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
a: self.a.clone(),
|
||||
b: self.b.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user