diff --git a/src/cursor.rs b/src/cursor.rs index 8bd6454..eb6dbcf 100644 --- a/src/cursor.rs +++ b/src/cursor.rs @@ -9,6 +9,13 @@ use ffi; use flags::WriteFlags; use transaction::Transaction; +// A type alias to a boxed trait object representing an Iterator over +// key/pair results. The Iter struct implements this trait, and we return +// the trait object instead of the Iter itself from Cursor.iter*() methods +// to delay returning an error until the consumer actually iterates +// or collects the Iter. +type BoxedIter<'txn> = Box>>; + /// An LMDB cursor. pub trait Cursor<'txn> { @@ -57,7 +64,7 @@ pub trait Cursor<'txn> { /// For databases with duplicate data items (`DatabaseFlags::DUP_SORT`), the /// duplicate data items of each key will be returned before moving on to /// the next key. - fn iter_from(&mut self, key: K) -> Box>> where K: AsRef<[u8]> { + fn iter_from(&mut self, key: K) -> BoxedIter where K: AsRef<[u8]> { match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) { Ok(_) | Err(Error::NotFound) => (), Err(error) => return Box::new(iter::once(Err(error))), @@ -80,16 +87,16 @@ pub trait Cursor<'txn> { /// Iterate over duplicate items in the database starting from the given /// key. Each item will be returned as an iterator of its duplicates. - fn iter_dup_from(&mut self, key: &K) -> Result> where K: AsRef<[u8]> { + fn iter_dup_from(&mut self, key: &K) -> Box> where K: AsRef<[u8]> { match self.get(Some(key.as_ref()), None, ffi::MDB_SET_RANGE) { Ok(_) | Err(Error::NotFound) => (), - Err(error) => return Err(error), + Err(error) => return Box::new(iter::once::(Box::new(iter::once(Err(error))))), }; - Ok(IterDup::new(self.cursor(), ffi::MDB_GET_CURRENT)) + Box::new(IterDup::new(self.cursor(), ffi::MDB_GET_CURRENT)) } /// Iterate over the duplicates of the item in the database with the given key. - fn iter_dup_of(&mut self, key: &K) -> Box>> where K: AsRef<[u8]> { + fn iter_dup_of(&mut self, key: &K) -> BoxedIter where K: AsRef<[u8]> { match self.get(Some(key.as_ref()), None, ffi::MDB_SET) { Ok(_) | Err(Error::NotFound) => (), Err(error) => return Box::new(iter::once(Err(error))), @@ -282,9 +289,9 @@ impl <'txn> fmt::Debug for IterDup<'txn> { impl <'txn> Iterator for IterDup<'txn> { - type Item = Iter<'txn>; + type Item = BoxedIter<'txn>; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option> { let mut key = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() }; let mut data = ffi::MDB_val { mv_size: 0, mv_data: ptr::null_mut() }; let op = mem::replace(&mut self.op, ffi::MDB_NEXT_NODUP); @@ -293,7 +300,7 @@ impl <'txn> Iterator for IterDup<'txn> { }; if err_code == ffi::MDB_SUCCESS { - Some(Iter::new(self.cursor, ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP)) + Some(Box::new(Iter::new(self.cursor, ffi::MDB_GET_CURRENT, ffi::MDB_NEXT_DUP))) } else { None } @@ -495,7 +502,7 @@ mod test { assert_eq!(0, cursor.iter_from(b"foo").count()); assert_eq!(0, cursor.iter_dup().count()); assert_eq!(0, cursor.iter_dup_start().count()); - assert_eq!(0, cursor.iter_dup_from(b"foo").unwrap().count()); + assert_eq!(0, cursor.iter_dup_from(b"foo").count()); assert_eq!(0, cursor.iter_dup_of(b"foo").count()); } @@ -538,16 +545,16 @@ mod test { cursor.iter_dup_start().flat_map(|x| x).collect::>>().unwrap()); assert_eq!(items.clone().into_iter().skip(3).collect::>(), - cursor.iter_dup_from(b"b").unwrap().flat_map(|x| x).collect::>>().unwrap()); + cursor.iter_dup_from(b"b").flat_map(|x| x).collect::>>().unwrap()); assert_eq!(items.clone().into_iter().skip(3).collect::>(), - cursor.iter_dup_from(b"ab").unwrap().flat_map(|x| x).collect::>>().unwrap()); + cursor.iter_dup_from(b"ab").flat_map(|x| x).collect::>>().unwrap()); assert_eq!(items.clone().into_iter().skip(9).collect::>(), - cursor.iter_dup_from(b"d").unwrap().flat_map(|x| x).collect::>>().unwrap()); + cursor.iter_dup_from(b"d").flat_map(|x| x).collect::>>().unwrap()); assert_eq!(vec!().into_iter().collect::>(), - cursor.iter_dup_from(b"f").unwrap().flat_map(|x| x).collect::>>().unwrap()); + cursor.iter_dup_from(b"f").flat_map(|x| x).collect::>>().unwrap()); assert_eq!(items.clone().into_iter().skip(3).take(3).collect::>(), cursor.iter_dup_of(b"b").collect::>>().unwrap());