diff --git a/src/graph.rs b/src/graph.rs index 8d933ab..b2578c9 100644 --- a/src/graph.rs +++ b/src/graph.rs @@ -765,6 +765,14 @@ mod tests { super::parse(&wabt::wat2wasm(wat).expect("faled to parse wat!")[..]) } + fn validate_sample(module: &super::Module) { + let binary = super::generate(module); + wabt::Module::read_binary(&binary, &Default::default()) + .expect("Wabt failed to read final binary") + .validate() + .expect("Invalid module"); + } + #[test] fn smoky() { let sample = load_sample(r#" @@ -789,7 +797,7 @@ mod tests { #[test] fn table() { - let mut sample = load_sample(r#" + let mut sample = load_sample(r#" (module (import "env" "foo" (func $foo)) (func (param i32) @@ -836,4 +844,41 @@ mod tests { assert_eq!(ftype.params().len(), 1); } } + + #[test] + fn new_import() { + let mut sample = load_sample(r#" +(module + (type (;0;) (func)) + (type (;1;) (func (param i32 i32) (result i32))) + (import "env" "foo" (func (type 1))) + (func (param i32) + get_local 0 + i32.const 0 + call 0 + drop + ) +)"# + ); + + { + let type_ref_0 = sample.types.clone_ref(0); + + let mut tx = sample.funcs.begin_insert_not_until( + |f| match f.origin { + super::ImportedOrDeclared::Imported(_, _) => false, + _ => true, + } + ); + + tx.push(super::Func { + type_ref: type_ref_0, + origin: super::ImportedOrDeclared::Imported("env".to_owned(), "bar".to_owned()), + }); + + tx.done(); + } + + validate_sample(&sample); + } } \ No newline at end of file diff --git a/src/ref_list.rs b/src/ref_list.rs index 8de3813..2d0d3f2 100644 --- a/src/ref_list.rs +++ b/src/ref_list.rs @@ -158,7 +158,7 @@ impl RefList { } } - /// Start inserting after the condition match (or at the end). + /// Start inserting after the condition first matches (or at the end). /// /// Start inserting some entries in the list at he designated position. /// Returns transaction that can be populated with some entries. @@ -171,6 +171,19 @@ impl RefList { self.begin_insert(pos) } + /// Start inserting after the condition first no longer true (or at the end). + /// + /// Start inserting some entries in the list at he designated position. + /// Returns transaction that can be populated with some entries. + /// When transaction is finailized, all entries are inserted and + /// internal indices of other entries might be updated. + pub fn begin_insert_not_until(&mut self, mut f: F) -> InsertTransaction + where F : FnMut(&T) -> bool + { + let pos = self.items.iter().take_while(|rf| f(&**rf.read())).count(); + self.begin_insert(pos) + } + /// Get entry with index (checked). /// /// Can return None when index out of bounts. @@ -406,6 +419,26 @@ mod tests { assert_eq!(item30.order(), Some(4)); } + #[test] + fn insert_not_until() { + let mut list = RefList::::new(); + let item10 = list.push(10); + let item20 = list.push(20); + let item30 = list.push(30); + + let mut insert_tx = list.begin_insert_not_until(|i| *i <= 20); + + let item23 = insert_tx.push(23); + let item27 = insert_tx.push(27); + insert_tx.done(); + + assert_eq!(item10.order(), Some(0)); + assert_eq!(item20.order(), Some(1)); + assert_eq!(item23.order(), Some(2)); + assert_eq!(item27.order(), Some(3)); + assert_eq!(item30.order(), Some(4)); + } + #[test] fn insert_after_none() { let mut list = RefList::::new(); @@ -426,6 +459,26 @@ mod tests { assert_eq!(item59.order(), Some(4)); } + #[test] + fn insert_not_until_none() { + let mut list = RefList::::new(); + let item10 = list.push(10); + let item20 = list.push(20); + let item30 = list.push(30); + + let mut insert_tx = list.begin_insert_not_until(|i| *i < 50); + + let item55 = insert_tx.push(23); + let item59 = insert_tx.push(27); + insert_tx.done(); + + assert_eq!(item10.order(), Some(0)); + assert_eq!(item20.order(), Some(1)); + assert_eq!(item30.order(), Some(2)); + assert_eq!(item55.order(), Some(3)); + assert_eq!(item59.order(), Some(4)); + } + #[test] fn insert_after_empty() { let mut list = RefList::::new();