wasmi/src/imports.rs

324 lines
8.8 KiB
Rust
Raw Normal View History

#[allow(unused_imports)]
use alloc::prelude::*;
#[cfg(feature = "std")]
2018-01-17 15:32:33 +00:00
use std::collections::HashMap;
#[cfg(not(feature = "std"))]
use hashmap_core::HashMap;
2018-01-17 15:32:33 +00:00
use global::GlobalRef;
use memory::MemoryRef;
use func::FuncRef;
use table::TableRef;
use module::ModuleRef;
2018-01-22 13:34:32 +00:00
use types::{GlobalDescriptor, TableDescriptor, MemoryDescriptor};
2018-01-18 12:48:43 +00:00
use {Error, Signature};
2018-01-17 15:32:33 +00:00
2018-01-24 15:49:42 +00:00
/// Resolver of a module's dependencies.
///
/// A module have dependencies in a form of a list of imports (i.e.
/// tuple of a (`module_name`, `field_name`, `descriptor`)).
///
/// The job of implementations of this trait is to provide on each
/// import a corresponding concrete reference.
2018-01-25 15:10:39 +00:00
///
/// For simple use-cases you can use [`ImportsBuilder`].
///
/// [`ImportsBuilder`]: struct.ImportsBuilder.html
2018-01-17 15:32:33 +00:00
pub trait ImportResolver {
2018-01-24 15:49:42 +00:00
/// Resolve a function.
///
/// Returned function should match given `signature`, i.e. all parameter types and return value should have exact match.
/// Otherwise, link-time error will occur.
2018-01-17 15:32:33 +00:00
fn resolve_func(
&self,
2018-01-24 15:49:42 +00:00
_module_name: &str,
2018-01-17 15:32:33 +00:00
field_name: &str,
2018-01-24 15:49:42 +00:00
_signature: &Signature,
2018-01-17 15:32:33 +00:00
) -> Result<FuncRef, Error>;
2018-01-24 15:49:42 +00:00
/// Resolve a global variable.
///
/// Returned global should match given `descriptor`, i.e. type and mutability
/// should match. Otherwise, link-time error will occur.
2018-01-17 15:32:33 +00:00
fn resolve_global(
&self,
module_name: &str,
field_name: &str,
2018-01-24 15:49:42 +00:00
descriptor: &GlobalDescriptor,
2018-01-17 15:32:33 +00:00
) -> Result<GlobalRef, Error>;
2018-01-24 15:49:42 +00:00
/// Resolve a memory.
///
/// Returned memory should match requested memory (described by the `descriptor`),
/// i.e. initial size of a returned memory should be equal or larger than requested memory.
/// Furthermore, if requested memory have maximum size, returned memory either should have
/// equal or larger maximum size or have no maximum size at all.
/// If returned memory doesn't match the requested then link-time error will occur.
2018-01-17 15:32:33 +00:00
fn resolve_memory(
&self,
module_name: &str,
field_name: &str,
2018-01-24 15:49:42 +00:00
descriptor: &MemoryDescriptor,
2018-01-17 15:32:33 +00:00
) -> Result<MemoryRef, Error>;
2018-01-24 15:49:42 +00:00
/// Resolve a table.
///
/// Returned table should match requested table (described by the `descriptor`),
/// i.e. initial size of a returned table should be equal or larger than requested table.
/// Furthermore, if requested memory have maximum size, returned memory either should have
/// equal or larger maximum size or have no maximum size at all.
/// If returned table doesn't match the requested then link-time error will occur.
2018-01-17 15:32:33 +00:00
fn resolve_table(
&self,
module_name: &str,
field_name: &str,
2018-01-24 15:49:42 +00:00
descriptor: &TableDescriptor,
2018-01-17 15:32:33 +00:00
) -> Result<TableRef, Error>;
}
2018-01-24 15:49:42 +00:00
/// Convenience builder of [`ImportResolver`].
///
/// With help of this builder, you can easily create [`ImportResolver`], just by
/// adding needed [resolvers][`ModuleImportResolver`] by names.
///
/// # Examples
///
/// ```rust
/// use wasmi::{ModuleInstance, ImportsBuilder};
2018-01-24 15:49:42 +00:00
/// #
/// # struct EnvModuleResolver;
/// # impl ::wasmi::ModuleImportResolver for EnvModuleResolver { }
/// # fn func() -> Result<(), ::wasmi::Error> {
/// # let module = wasmi::Module::from_buffer(&[0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00]).unwrap();
2018-01-24 15:49:42 +00:00
/// # let other_instance = ModuleInstance::new(&module, &ImportsBuilder::default())?.assert_no_start();
///
/// let imports = ImportsBuilder::new()
2018-01-25 16:56:52 +00:00
/// .with_resolver("env", &EnvModuleResolver)
/// // Note, that ModuleInstance can be a resolver too.
/// .with_resolver("other_instance", &other_instance);
2018-01-24 15:49:42 +00:00
/// let instance = ModuleInstance::new(&module, &imports)?.assert_no_start();
///
/// # Ok(())
/// # }
/// ```
///
/// [`ImportResolver`]: trait.ImportResolver.html
/// [`ModuleImportResolver`]: trait.ModuleImportResolver.html
2018-01-17 15:32:33 +00:00
pub struct ImportsBuilder<'a> {
modules: HashMap<String, &'a ModuleImportResolver>,
}
impl<'a> Default for ImportsBuilder<'a> {
fn default() -> Self {
Self::new()
}
}
impl<'a> ImportsBuilder<'a> {
2018-01-24 15:49:42 +00:00
/// Create an empty `ImportsBuilder`.
2018-01-17 15:32:33 +00:00
pub fn new() -> ImportsBuilder<'a> {
ImportsBuilder { modules: HashMap::new() }
}
2018-01-24 15:49:42 +00:00
/// Register an resolver by a name.
2018-01-17 15:32:33 +00:00
pub fn with_resolver<N: Into<String>>(
mut self,
name: N,
resolver: &'a ModuleImportResolver,
) -> Self {
self.modules.insert(name.into(), resolver);
self
}
2018-01-24 15:49:42 +00:00
/// Register an resolver by a name.
///
/// Mutable borrowed version.
2018-01-17 15:32:33 +00:00
pub fn push_resolver<N: Into<String>>(&mut self, name: N, resolver: &'a ModuleImportResolver) {
self.modules.insert(name.into(), resolver);
}
2018-01-24 15:49:42 +00:00
fn resolver(&self, name: &str) -> Option<&ModuleImportResolver> {
2018-01-17 15:32:33 +00:00
self.modules.get(name).cloned()
}
}
impl<'a> ImportResolver for ImportsBuilder<'a> {
fn resolve_func(
&self,
module_name: &str,
field_name: &str,
2018-01-18 12:48:43 +00:00
signature: &Signature,
2018-01-17 15:32:33 +00:00
) -> Result<FuncRef, Error> {
self.resolver(module_name).ok_or_else(||
Error::Instantiation(format!("Module {} not found", module_name))
2018-01-18 12:48:43 +00:00
)?.resolve_func(field_name, signature)
2018-01-17 15:32:33 +00:00
}
fn resolve_global(
&self,
module_name: &str,
field_name: &str,
2018-01-22 13:23:07 +00:00
global_type: &GlobalDescriptor,
2018-01-17 15:32:33 +00:00
) -> Result<GlobalRef, Error> {
self.resolver(module_name).ok_or_else(||
Error::Instantiation(format!("Module {} not found", module_name))
)?.resolve_global(field_name, global_type)
}
fn resolve_memory(
&self,
module_name: &str,
field_name: &str,
2018-01-22 13:34:32 +00:00
memory_type: &MemoryDescriptor,
2018-01-17 15:32:33 +00:00
) -> Result<MemoryRef, Error> {
self.resolver(module_name).ok_or_else(||
Error::Instantiation(format!("Module {} not found", module_name))
)?.resolve_memory(field_name, memory_type)
}
fn resolve_table(
&self,
module_name: &str,
field_name: &str,
2018-01-22 13:30:13 +00:00
table_type: &TableDescriptor,
2018-01-17 15:32:33 +00:00
) -> Result<TableRef, Error> {
self.resolver(module_name).ok_or_else(||
Error::Instantiation(format!("Module {} not found", module_name))
)?.resolve_table(field_name, table_type)
}
}
2018-01-24 15:49:42 +00:00
/// Version of [`ImportResolver`] specialized for a single module.
///
/// [`ImportResolver`]: trait.ImportResolver.html
2018-01-17 15:32:33 +00:00
pub trait ModuleImportResolver {
2018-01-24 15:49:42 +00:00
/// Resolve a function.
///
/// See [`ImportResolver::resolve_func`] for details.
///
/// [`ImportResolver::resolve_func`]: trait.ImportResolver.html#tymethod.resolve_func
2018-01-17 15:32:33 +00:00
fn resolve_func(
&self,
field_name: &str,
2018-01-18 12:48:43 +00:00
_signature: &Signature,
2018-01-17 15:32:33 +00:00
) -> Result<FuncRef, Error> {
Err(Error::Instantiation(
format!("Export {} not found", field_name),
))
}
2018-01-24 15:49:42 +00:00
/// Resolve a global variable.
///
/// See [`ImportResolver::resolve_global`] for details.
///
/// [`ImportResolver::resolve_global`]: trait.ImportResolver.html#tymethod.resolve_global
2018-01-17 15:32:33 +00:00
fn resolve_global(
&self,
field_name: &str,
2018-01-22 13:23:07 +00:00
_global_type: &GlobalDescriptor,
2018-01-17 15:32:33 +00:00
) -> Result<GlobalRef, Error> {
Err(Error::Instantiation(
format!("Export {} not found", field_name),
))
}
2018-01-24 15:49:42 +00:00
/// Resolve a memory.
///
/// See [`ImportResolver::resolve_memory`] for details.
///
/// [`ImportResolver::resolve_memory`]: trait.ImportResolver.html#tymethod.resolve_memory
2018-01-17 15:32:33 +00:00
fn resolve_memory(
&self,
field_name: &str,
2018-01-22 13:34:32 +00:00
_memory_type: &MemoryDescriptor,
2018-01-17 15:32:33 +00:00
) -> Result<MemoryRef, Error> {
Err(Error::Instantiation(
format!("Export {} not found", field_name),
))
}
2018-01-24 15:49:42 +00:00
/// Resolve a table.
///
/// See [`ImportResolver::resolve_table`] for details.
///
/// [`ImportResolver::resolve_table`]: trait.ImportResolver.html#tymethod.resolve_table
2018-01-17 15:32:33 +00:00
fn resolve_table(
&self,
field_name: &str,
2018-01-22 13:30:13 +00:00
_table_type: &TableDescriptor,
2018-01-17 15:32:33 +00:00
) -> Result<TableRef, Error> {
Err(Error::Instantiation(
format!("Export {} not found", field_name),
))
}
}
impl ModuleImportResolver for ModuleRef {
fn resolve_func(
&self,
field_name: &str,
2018-01-18 12:48:43 +00:00
_signature: &Signature,
2018-01-17 15:32:33 +00:00
) -> Result<FuncRef, Error> {
Ok(self.export_by_name(field_name)
.ok_or_else(|| {
Error::Instantiation(format!("Export {} not found", field_name))
})?
.as_func()
2018-01-25 15:10:39 +00:00
.cloned()
2018-01-17 15:32:33 +00:00
.ok_or_else(|| {
Error::Instantiation(format!("Export {} is not a function", field_name))
})?)
}
fn resolve_global(
&self,
field_name: &str,
2018-01-22 13:23:07 +00:00
_global_type: &GlobalDescriptor,
2018-01-17 15:32:33 +00:00
) -> Result<GlobalRef, Error> {
Ok(self.export_by_name(field_name)
.ok_or_else(|| {
Error::Instantiation(format!("Export {} not found", field_name))
})?
.as_global()
2018-01-25 15:10:39 +00:00
.cloned()
2018-01-17 15:32:33 +00:00
.ok_or_else(|| {
Error::Instantiation(format!("Export {} is not a global", field_name))
})?)
}
fn resolve_memory(
&self,
field_name: &str,
2018-01-22 13:34:32 +00:00
_memory_type: &MemoryDescriptor,
2018-01-17 15:32:33 +00:00
) -> Result<MemoryRef, Error> {
Ok(self.export_by_name(field_name)
.ok_or_else(|| {
Error::Instantiation(format!("Export {} not found", field_name))
})?
.as_memory()
2018-01-25 15:10:39 +00:00
.cloned()
2018-01-17 15:32:33 +00:00
.ok_or_else(|| {
Error::Instantiation(format!("Export {} is not a memory", field_name))
})?)
}
fn resolve_table(
&self,
field_name: &str,
2018-01-22 13:30:13 +00:00
_table_type: &TableDescriptor,
2018-01-17 15:32:33 +00:00
) -> Result<TableRef, Error> {
Ok(self.export_by_name(field_name)
.ok_or_else(|| {
Error::Instantiation(format!("Export {} not found", field_name))
})?
.as_table()
2018-01-25 15:10:39 +00:00
.cloned()
2018-01-17 15:32:33 +00:00
.ok_or_else(|| {
Error::Instantiation(format!("Export {} is not a table", field_name))
})?)
}
}