Use Iterators for ExternVal imports

This commit is contained in:
Sergey Pepyakin 2018-03-29 17:26:41 +03:00
parent c8ff919c5c
commit ccd85a51cd
1 changed files with 74 additions and 17 deletions

View File

@ -213,9 +213,9 @@ impl ModuleInstance {
self.exports.borrow_mut().insert(name.into(), extern_val); self.exports.borrow_mut().insert(name.into(), extern_val);
} }
fn alloc_module( fn alloc_module<'i, I: Iterator<Item = &'i ExternVal>>(
loaded_module: &Module, loaded_module: &Module,
extern_vals: &[ExternVal] extern_vals: I,
) -> Result<ModuleRef, Error> { ) -> Result<ModuleRef, Error> {
let module = loaded_module.module(); let module = loaded_module.module();
let instance = ModuleRef(Rc::new(ModuleInstance::default())); let instance = ModuleRef(Rc::new(ModuleInstance::default()));
@ -226,18 +226,26 @@ impl ModuleInstance {
} }
{ {
let imports = module.import_section().map(|is| is.entries()).unwrap_or( let mut imports = module
&[], .import_section()
); .map(|is| is.entries())
if imports.len() != extern_vals.len() { .unwrap_or(&[])
return Err(Error::Instantiation( .into_iter();
"extern_vals length is not equal to import section entries".to_owned() let mut extern_vals = extern_vals;
)); loop {
} // Iterate on imports and extern_vals in lockstep, a-la `Iterator:zip`.
// We can't use `Iterator::zip` since we want to check if lengths of both iterators are same and
// `Iterator::zip` just returns `None` if either of iterators return `None`.
let (import, extern_val) = match (imports.next(), extern_vals.next()) {
(Some(import), Some(extern_val)) => (import, extern_val),
(None, None) => break,
(Some(_), None) | (None, Some(_)) => {
return Err(Error::Instantiation(
"extern_vals length is not equal to import section entries".to_owned(),
));
}
};
for (import, extern_val) in
Iterator::zip(imports.into_iter(), extern_vals.into_iter())
{
match (import.external(), extern_val) { match (import.external(), extern_val) {
(&External::Function(fn_type_idx), &ExternVal::Func(ref func)) => { (&External::Function(fn_type_idx), &ExternVal::Func(ref func)) => {
let expected_fn_type = instance.signature_by_index(fn_type_idx).expect( let expected_fn_type = instance.signature_by_index(fn_type_idx).expect(
@ -389,9 +397,9 @@ impl ModuleInstance {
/// ///
/// [new]: #method.new /// [new]: #method.new
/// [ExternVal]: https://webassembly.github.io/spec/core/exec/runtime.html#syntax-externval /// [ExternVal]: https://webassembly.github.io/spec/core/exec/runtime.html#syntax-externval
pub fn with_externvals<'a>( pub fn with_externvals<'a, 'i, I: Iterator<Item = &'i ExternVal>>(
loaded_module: &'a Module, loaded_module: &'a Module,
extern_vals: &[ExternVal], extern_vals: I,
) -> Result<NotStartedModuleRef<'a>, Error> { ) -> Result<NotStartedModuleRef<'a>, Error> {
let module = loaded_module.module(); let module = loaded_module.module();
@ -544,7 +552,7 @@ impl ModuleInstance {
extern_vals.push(extern_val); extern_vals.push(extern_val);
} }
Self::with_externvals(loaded_module, &extern_vals) Self::with_externvals(loaded_module, extern_vals.iter())
} }
/// Invoke exported function by a name. /// Invoke exported function by a name.
@ -757,7 +765,9 @@ pub fn check_limits(limits: &ResizableLimits) -> Result<(), Error> {
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use imports::ImportsBuilder; use imports::ImportsBuilder;
use super::{ModuleInstance}; use func::FuncInstance;
use types::{Signature, ValueType};
use super::{ModuleInstance, ExternVal};
use tests::parse_wat; use tests::parse_wat;
#[should_panic] #[should_panic]
@ -775,4 +785,51 @@ mod tests {
&ImportsBuilder::default() &ImportsBuilder::default()
).unwrap().assert_no_start(); ).unwrap().assert_no_start();
} }
#[test]
fn imports_provided_by_externvals() {
let module_with_single_import = parse_wat(
r#"
(module
(import "foo" "bar" (func))
)
"#,
);
assert!(
ModuleInstance::with_externvals(
&module_with_single_import,
[
ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0),)
].iter(),
).is_ok()
);
// externval vector is longer than import count.
assert!(
ModuleInstance::with_externvals(
&module_with_single_import,
[
ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 0)),
ExternVal::Func(FuncInstance::alloc_host(Signature::new(&[][..], None), 1)),
].iter(),
).is_err()
);
// externval vector is shorter than import count.
assert!(ModuleInstance::with_externvals(&module_with_single_import, [].iter(),).is_err());
// externval vector has an unexpected type.
assert!(
ModuleInstance::with_externvals(
&module_with_single_import,
[
ExternVal::Func(FuncInstance::alloc_host(
Signature::new(&[][..], Some(ValueType::I32)),
0
),)
].iter(),
).is_err()
);
}
} }