diff --git a/lib/revisionstore/src/datapack.rs b/lib/revisionstore/src/datapack.rs index 7607b88034..ee619e66f3 100644 --- a/lib/revisionstore/src/datapack.rs +++ b/lib/revisionstore/src/datapack.rs @@ -87,6 +87,7 @@ use datastore::{DataStore, Delta, Metadata}; use error::Result; use key::Key; use node::Node; +use repack::IterableStore; #[derive(Debug, Fail)] #[fail(display = "Datapack Error: {:?}", _0)] @@ -357,6 +358,44 @@ impl DataStore for DataPack { } } +impl IterableStore for DataPack { + fn iter<'a>(&'a self) -> Box> + 'a> { + Box::new(DataPackIterator::new(self)) + } +} + +struct DataPackIterator<'a> { + pack: &'a DataPack, + offset: u64, +} + +impl<'a> DataPackIterator<'a> { + pub fn new(pack: &'a DataPack) -> Self { + DataPackIterator { + pack: pack, + offset: 1, // Start after the header byte + } + } +} + +impl<'a> Iterator for DataPackIterator<'a> { + type Item = Result; + + fn next(&mut self) -> Option { + if self.offset as usize >= self.pack.len() { + return None; + } + let entry = self.pack.read_entry(self.offset); + Some(match entry { + Ok(ref e) => { + self.offset = e.next_offset; + Ok(Key::new(e.filename.to_vec().into_boxed_slice(), e.node)) + } + Err(e) => Err(e), + }) + } +} + #[cfg(test)] mod tests { use super::*; @@ -562,4 +601,64 @@ mod tests { assert_eq!(&chains[i], &chain); } } + + #[test] + fn test_iter() { + let mut rng = ChaChaRng::from_seed([0u8; 32]); + let tempdir = TempDir::new().unwrap(); + + let revisions = vec![ + ( + Delta { + data: Rc::new([1, 2, 3, 4]), + base: Some(Key::new(Box::new([0]), Node::random(&mut rng))), + key: Key::new(Box::new([0]), Node::random(&mut rng)), + }, + None, + ), + ( + Delta { + data: Rc::new([1, 2, 3, 4]), + base: Some(Key::new(Box::new([0]), Node::random(&mut rng))), + key: Key::new(Box::new([0]), Node::random(&mut rng)), + }, + None, + ), + ]; + + let pack = make_pack(&tempdir, &revisions); + assert_eq!( + pack.iter().collect::>>().unwrap(), + revisions + .iter() + .map(|d| d.0.key.clone()) + .collect::>() + ); + } + + quickcheck! { + fn test_iter_quickcheck(keys: Vec<(Vec, Key)>) -> bool { + let tempdir = TempDir::new().unwrap(); + + let mut revisions: Vec<(Delta, Option)> = vec![]; + for (data, key) in keys { + revisions.push(( + Delta { + data: Rc::from(data.clone()), + base: None, + key: key.clone(), + }, + None, + )); + } + + let pack = make_pack(&tempdir, &revisions); + let same = pack.iter().collect::>>().unwrap() + == revisions + .iter() + .map(|d| d.0.key.clone()) + .collect::>(); + same + } + } } diff --git a/lib/revisionstore/src/lib.rs b/lib/revisionstore/src/lib.rs index 413f65b943..249650a06d 100644 --- a/lib/revisionstore/src/lib.rs +++ b/lib/revisionstore/src/lib.rs @@ -28,5 +28,6 @@ pub mod key; pub mod loosefile; pub mod mutabledatapack; pub mod node; +pub mod repack; pub mod uniondatastore; pub mod unionhistorystore; diff --git a/lib/revisionstore/src/repack.rs b/lib/revisionstore/src/repack.rs new file mode 100644 index 0000000000..bff7278c59 --- /dev/null +++ b/lib/revisionstore/src/repack.rs @@ -0,0 +1,6 @@ +use error::Result; +use key::Key; + +pub trait IterableStore { + fn iter<'a>(&'a self) -> Box> + 'a>; +}