mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-10 14:48:27 +00:00
Unify Imports in wasmer js/sys
This commit is contained in:
@@ -1,10 +1,9 @@
|
||||
//! The import module contains the implementation data structures and helper functions used to
|
||||
//! manipulate and access a wasm module's imports including memories, tables, globals, and
|
||||
//! functions.
|
||||
use crate::{Exports, Extern, Module};
|
||||
use crate::{Exports, Extern, LinkError, Module};
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use wasmer_compiler::LinkError;
|
||||
use wasmer_types::ImportError;
|
||||
|
||||
/// All of the import data used when instantiating.
|
||||
@@ -36,7 +35,7 @@ use wasmer_types::ImportError;
|
||||
/// ```
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Imports {
|
||||
map: HashMap<(String, String), Extern>,
|
||||
pub(crate) map: HashMap<(String, String), Extern>,
|
||||
}
|
||||
|
||||
impl Imports {
|
||||
@@ -306,10 +305,10 @@ macro_rules! import_namespace {
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::store::{AsStoreMut, Store};
|
||||
use crate::sys::Global;
|
||||
use crate::value::Value;
|
||||
use crate::Extern;
|
||||
use crate::Global;
|
||||
use wasmer_types::Type;
|
||||
use wasmer_vm::VMExtern;
|
||||
|
||||
#[test]
|
||||
fn namespace() {
|
||||
@@ -324,18 +323,16 @@ mod test {
|
||||
|
||||
let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
|
||||
|
||||
assert!(
|
||||
if let VMExtern::Global(happy_dog_global) = happy_dog_entry.to_vm_extern() {
|
||||
(*happy_dog_global.get(store.objects_mut()).ty()).ty == Type::I32
|
||||
assert!(if let Extern::Global(happy_dog_global) = happy_dog_entry {
|
||||
happy_dog_global.get(&mut store).ty() == Type::I32
|
||||
} else {
|
||||
false
|
||||
}
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn imports_macro_allows_trailing_comma_and_none() {
|
||||
use crate::sys::Function;
|
||||
use crate::Function;
|
||||
|
||||
let mut store: Store = Default::default();
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
//use crate::js::externals::Function;
|
||||
// use crate::store::{Store, StoreObject};
|
||||
// use crate::js::RuntimeError;
|
||||
use crate::imports::Imports;
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::imports::Imports;
|
||||
use crate::js::vm::VMExtern;
|
||||
use crate::store::{AsStoreMut, AsStoreRef};
|
||||
use crate::value::Value;
|
||||
|
||||
@@ -1,352 +0,0 @@
|
||||
//! The import module contains the implementation data structures and helper functions used to
|
||||
//! manipulate and access a wasm module's imports including memories, tables, globals, and
|
||||
//! functions.
|
||||
use crate::exports::Exports;
|
||||
use crate::js::error::{LinkError, WasmError};
|
||||
use crate::js::module::Module;
|
||||
use crate::store::{AsStoreMut, AsStoreRef};
|
||||
use crate::Extern;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use wasmer_types::ImportError;
|
||||
|
||||
/// All of the import data used when instantiating.
|
||||
///
|
||||
/// It's suggested that you use the [`imports!`] macro
|
||||
/// instead of creating an `Imports` by hand.
|
||||
///
|
||||
/// [`imports!`]: macro.imports.html
|
||||
///
|
||||
/// # Usage:
|
||||
/// ```no_run
|
||||
/// use wasmer::{Exports, Module, Store, Instance, imports, Imports, Function};
|
||||
/// # fn foo_test(module: Module, store: Store) {
|
||||
///
|
||||
/// let host_fn = Function::new_typed(foo);
|
||||
/// let import_object: Imports = imports! {
|
||||
/// "env" => {
|
||||
/// "foo" => host_fn,
|
||||
/// },
|
||||
/// };
|
||||
///
|
||||
/// let instance = Instance::new(&module, &import_object).expect("Could not instantiate module.");
|
||||
///
|
||||
/// fn foo(n: i32) -> i32 {
|
||||
/// n
|
||||
/// }
|
||||
///
|
||||
/// # }
|
||||
/// ```
|
||||
#[derive(Clone, Default)]
|
||||
pub struct Imports {
|
||||
pub(crate) map: HashMap<(String, String), Extern>,
|
||||
}
|
||||
|
||||
impl Imports {
|
||||
/// Create a new `Imports`.
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
|
||||
/// Gets an export given a ns and a name
|
||||
///
|
||||
/// # Usage
|
||||
/// ```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<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.clone());
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
/// Returns true if the Imports contains namespace with the provided name.
|
||||
pub fn contains_namespace(&self, name: &str) -> bool {
|
||||
self.map.keys().any(|(k, _)| (k == name))
|
||||
}
|
||||
|
||||
/// 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,
|
||||
contents: impl IntoIterator<Item = (String, Extern)>,
|
||||
) {
|
||||
for (name, extern_) in contents.into_iter() {
|
||||
self.map.insert((ns.to_string(), name.clone()), extern_);
|
||||
}
|
||||
}
|
||||
|
||||
/// Add a single import with a namespace `ns` and name `name`.
|
||||
///
|
||||
/// # Usage
|
||||
/// ```no_run
|
||||
/// # let mut 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_typed(&store, 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());
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
}
|
||||
|
||||
/// 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,
|
||||
_store: &mut impl AsStoreMut,
|
||||
) -> Result<Vec<Extern>, LinkError> {
|
||||
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(LinkError::Import(
|
||||
import.module().to_string(),
|
||||
import.name().to_string(),
|
||||
ImportError::UnknownImport(import.ty().clone()),
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(ret)
|
||||
}
|
||||
|
||||
/// Iterates through all the imports in this structure
|
||||
pub fn iter<'a>(&'a self) -> ImportsIterator<'a> {
|
||||
ImportsIterator::new(self)
|
||||
}
|
||||
|
||||
/// Create a new `Imports` from a JS Object, it receives a reference to a `Module` to
|
||||
/// map and assign the types of each import and the JS Object
|
||||
/// that contains the values of imports.
|
||||
///
|
||||
/// # Usage
|
||||
/// ```ignore
|
||||
/// let import_object = Imports::new_from_js_object(&mut store, &module, js_object);
|
||||
/// ```
|
||||
pub fn new_from_js_object(
|
||||
store: &mut impl AsStoreMut,
|
||||
module: &Module,
|
||||
object: js_sys::Object,
|
||||
) -> Result<Self, WasmError> {
|
||||
unimplemented!();
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ImportsIterator<'a> {
|
||||
iter: std::collections::hash_map::Iter<'a, (String, String), Extern>,
|
||||
}
|
||||
|
||||
impl<'a> ImportsIterator<'a> {
|
||||
fn new(imports: &'a Imports) -> Self {
|
||||
let iter = imports.map.iter();
|
||||
Self { iter }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for ImportsIterator<'a> {
|
||||
type Item = (&'a str, &'a str, &'a Extern);
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
self.iter
|
||||
.next()
|
||||
.map(|(k, v)| (k.0.as_str(), k.1.as_str(), v))
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoIterator for &Imports {
|
||||
type IntoIter = std::collections::hash_map::IntoIter<(String, String), Extern>;
|
||||
type Item = ((String, String), Extern);
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
self.map.clone().into_iter()
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
Empty,
|
||||
Some(usize),
|
||||
}
|
||||
|
||||
impl SecretMap {
|
||||
fn new(len: usize) -> Self {
|
||||
if len == 0 {
|
||||
Self::Empty
|
||||
} else {
|
||||
Self::Some(len)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for SecretMap {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match self {
|
||||
Self::Empty => write!(f, "(empty)"),
|
||||
Self::Some(len) => write!(f, "(... {} item(s) ...)", len),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
f.debug_struct("Imports")
|
||||
.field("map", &SecretMap::new(self.map.len()))
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
// The import! macro for Imports
|
||||
|
||||
/// Generate an [`Imports`] easily with the `imports!` macro.
|
||||
///
|
||||
/// [`Imports`]: struct.Imports.html
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Function, Store};
|
||||
/// # let mut store = Store::default();
|
||||
/// use wasmer::imports;
|
||||
///
|
||||
/// let import_object = imports! {
|
||||
/// "env" => {
|
||||
/// "foo" => Function::new_typed(&store, foo)
|
||||
/// },
|
||||
/// };
|
||||
///
|
||||
/// fn foo(n: i32) -> i32 {
|
||||
/// n
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! imports {
|
||||
( $( $ns_name:expr => $ns:tt ),* $(,)? ) => {
|
||||
{
|
||||
let mut import_object = $crate::Imports::new();
|
||||
|
||||
$({
|
||||
let namespace = $crate::import_namespace!($ns);
|
||||
|
||||
import_object.register_namespace($ns_name, namespace);
|
||||
})*
|
||||
|
||||
import_object
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! namespace {
|
||||
($( $import_name:expr => $import_item:expr ),* $(,)? ) => {
|
||||
$crate::import_namespace!( { $( $import_name => $import_item, )* } )
|
||||
};
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! import_namespace {
|
||||
( { $( $import_name:expr => $import_item:expr ),* $(,)? } ) => {{
|
||||
let mut namespace = $crate::Exports::new();
|
||||
|
||||
$(
|
||||
namespace.insert($import_name, $import_item);
|
||||
)*
|
||||
|
||||
namespace
|
||||
}};
|
||||
|
||||
( $namespace:ident ) => {
|
||||
$namespace
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{Global, Store, Value};
|
||||
|
||||
// use wasm_bindgen::*;
|
||||
use wasm_bindgen_test::*;
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn chaining_works() {
|
||||
let mut store = Store::default();
|
||||
|
||||
let g = Global::new(&mut store, Value::I32(0));
|
||||
|
||||
let mut imports1 = imports! {
|
||||
"dog" => {
|
||||
"happy" => g.clone()
|
||||
}
|
||||
};
|
||||
|
||||
let imports2 = imports! {
|
||||
"dog" => {
|
||||
"small" => g.clone()
|
||||
},
|
||||
"cat" => {
|
||||
"small" => g
|
||||
}
|
||||
};
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::exports::Exports;
|
||||
use crate::imports::Imports;
|
||||
use crate::js::error::InstantiationError;
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::imports::Imports;
|
||||
use crate::js::vm::{VMExtern, VMInstance};
|
||||
use crate::module::Module;
|
||||
use crate::store::{AsStoreMut, AsStoreRef};
|
||||
|
||||
@@ -28,7 +28,6 @@ pub(crate) mod engine;
|
||||
pub(crate) mod error;
|
||||
pub(crate) mod extern_ref;
|
||||
pub(crate) mod externals;
|
||||
mod imports;
|
||||
mod instance;
|
||||
pub(crate) mod module;
|
||||
#[cfg(feature = "wasm-types-polyfill")]
|
||||
@@ -41,12 +40,11 @@ mod wasm_bindgen_polyfill;
|
||||
|
||||
pub use crate::js::as_js::AsJs;
|
||||
pub use crate::js::engine::Engine;
|
||||
pub use crate::js::error::{DeserializeError, InstantiationError, SerializeError};
|
||||
pub use crate::js::error::{DeserializeError, InstantiationError, LinkError, SerializeError};
|
||||
pub use crate::js::externals::{
|
||||
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, MemoryView,
|
||||
Table, WasmTypeList,
|
||||
};
|
||||
pub use crate::js::imports::Imports;
|
||||
pub use crate::js::instance::Instance;
|
||||
pub use crate::js::module::{Module, ModuleTypeHints};
|
||||
pub use crate::js::store::StoreObjects;
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
use crate::imports::Imports;
|
||||
use crate::js::error::InstantiationError;
|
||||
#[cfg(feature = "wat")]
|
||||
use crate::js::error::WasmError;
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::imports::Imports;
|
||||
use crate::js::vm::VMInstance;
|
||||
use crate::js::AsJs;
|
||||
use crate::js::RuntimeError;
|
||||
|
||||
@@ -433,6 +433,7 @@ mod engine;
|
||||
mod exports;
|
||||
mod extern_ref;
|
||||
mod function_env;
|
||||
mod imports;
|
||||
mod into_bytes;
|
||||
mod mem_access;
|
||||
mod module;
|
||||
@@ -458,6 +459,7 @@ pub use engine::{AsEngineRef, Engine};
|
||||
pub use exports::{ExportError, Exportable, Exports, ExportsIterator};
|
||||
pub use extern_ref::ExternRef;
|
||||
pub use function_env::{FunctionEnv, FunctionEnvMut};
|
||||
pub use imports::Imports;
|
||||
pub use into_bytes::IntoBytes;
|
||||
pub use mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter};
|
||||
pub use module::{IoCompileError, Module};
|
||||
|
||||
@@ -5,8 +5,9 @@ use std::fmt;
|
||||
use thiserror::Error;
|
||||
use wasmer_vm::{StoreHandle, VMInstance};
|
||||
|
||||
use crate::imports::Imports;
|
||||
use crate::store::AsStoreMut;
|
||||
use crate::sys::{externals::Extern, imports::Imports};
|
||||
use crate::sys::externals::Extern;
|
||||
|
||||
/// A WebAssembly Instance is a stateful, executable
|
||||
/// instance of a WebAssembly [`Module`].
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
pub(crate) mod engine;
|
||||
pub(crate) mod extern_ref;
|
||||
pub(crate) mod externals;
|
||||
mod imports;
|
||||
mod instance;
|
||||
pub(crate) mod module;
|
||||
mod tunables;
|
||||
@@ -11,7 +10,6 @@ pub use crate::sys::externals::{
|
||||
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryView, Table,
|
||||
WasmTypeList,
|
||||
};
|
||||
pub use crate::sys::imports::Imports;
|
||||
pub use crate::sys::instance::{Instance, InstantiationError};
|
||||
|
||||
pub use crate::sys::tunables::BaseTunables;
|
||||
|
||||
Reference in New Issue
Block a user