mnem_core/prolly/
cursor.rs1use crate::error::Error;
13use crate::id::Cid;
14use crate::prolly::constants::ProllyKey;
15use crate::prolly::tree::{Internal, Leaf, TreeChunk, load_tree_chunk};
16use crate::store::Blockstore;
17
18pub struct Cursor<'a, B: Blockstore + ?Sized> {
23 store: &'a B,
24 stack: Vec<(Internal, usize)>,
27 current: Option<(Leaf, usize)>,
29}
30
31impl<'a, B: Blockstore + ?Sized> Cursor<'a, B> {
32 pub fn new(store: &'a B, root: &Cid) -> Result<Self, Error> {
38 let mut c = Self {
39 store,
40 stack: Vec::new(),
41 current: None,
42 };
43 c.descend(root)?;
44 Ok(c)
45 }
46
47 fn descend(&mut self, start: &Cid) -> Result<(), Error> {
51 let mut cid = start.clone();
52 loop {
53 match load_tree_chunk(self.store, &cid)? {
54 TreeChunk::Leaf(leaf) => {
55 self.current = Some((leaf, 0));
56 return Ok(());
57 }
58 TreeChunk::Internal(internal) => {
59 let next = internal.children[0].clone();
60 self.stack.push((internal, 1));
61 cid = next;
62 }
63 }
64 }
65 }
66
67 fn advance_leaf(&mut self) -> Result<bool, Error> {
70 loop {
71 let (internal, next_idx) = match self.stack.last_mut() {
72 Some(f) => f,
73 None => return Ok(false),
74 };
75 if *next_idx < internal.children.len() {
76 let next_cid = internal.children[*next_idx].clone();
77 *next_idx += 1;
78 self.descend(&next_cid)?;
79 return Ok(true);
80 }
81 self.stack.pop();
82 }
83 }
84}
85
86impl<B: Blockstore + ?Sized> Iterator for Cursor<'_, B> {
87 type Item = Result<(ProllyKey, Cid), Error>;
88
89 fn next(&mut self) -> Option<Self::Item> {
90 loop {
91 if let Some((leaf, idx)) = &mut self.current {
92 if *idx < leaf.entries.len() {
93 let (k, v) = leaf.entries[*idx].clone();
94 *idx += 1;
95 return Some(Ok((k, v)));
96 }
97 self.current = None;
98 }
99 match self.advance_leaf() {
100 Ok(true) => continue, Ok(false) => return None,
102 Err(e) => return Some(Err(e)),
103 }
104 }
105 }
106}
107
108#[cfg(test)]
109mod tests {
110 use super::*;
111 use crate::id::{CODEC_RAW, Multihash};
112 use crate::prolly::tree::build_tree;
113 use crate::store::MemoryBlockstore;
114
115 fn keyed(i: u32) -> ProllyKey {
116 let mut k = [0u8; 16];
117 k[12..16].copy_from_slice(&i.to_be_bytes());
118 ProllyKey(k)
119 }
120
121 fn val(i: u32) -> Cid {
122 Cid::new(CODEC_RAW, Multihash::sha2_256(&i.to_be_bytes()))
123 }
124
125 #[test]
126 fn cursor_iterates_empty_tree_to_nothing() {
127 let store = MemoryBlockstore::new();
128 let root = build_tree(&store, std::iter::empty()).unwrap();
129 let cursor = Cursor::new(&store, &root).unwrap();
130 let collected: Vec<_> = cursor.map(|r| r.unwrap()).collect();
131 assert!(collected.is_empty());
132 }
133
134 #[test]
135 fn cursor_iterates_single_entry() {
136 let store = MemoryBlockstore::new();
137 let root = build_tree(&store, [(keyed(7), val(42))]).unwrap();
138 let cursor = Cursor::new(&store, &root).unwrap();
139 let collected: Vec<_> = cursor.map(|r| r.unwrap()).collect();
140 assert_eq!(collected, vec![(keyed(7), val(42))]);
141 }
142
143 #[test]
144 fn cursor_iterates_single_leaf_in_key_order() {
145 let store = MemoryBlockstore::new();
146 let entries: Vec<_> = (0..10u32).map(|i| (keyed(i), val(i))).collect();
147 let root = build_tree(&store, entries.clone()).unwrap();
148 let cursor = Cursor::new(&store, &root).unwrap();
149 let collected: Vec<_> = cursor.map(|r| r.unwrap()).collect();
150 assert_eq!(collected, entries);
151 }
152
153 #[test]
154 fn cursor_iterates_multi_level_tree_in_key_order() {
155 let store = MemoryBlockstore::new();
156 let entries: Vec<_> = (0..5_000u32).map(|i| (keyed(i), val(i))).collect();
157 let root = build_tree(&store, entries.clone()).unwrap();
158 let cursor = Cursor::new(&store, &root).unwrap();
159 let collected: Vec<_> = cursor.map(|r| r.unwrap()).collect();
160 assert_eq!(collected.len(), 5_000);
161 for w in collected.windows(2) {
163 assert!(
164 w[0].0 < w[1].0,
165 "out-of-order: {:?} then {:?}",
166 w[0].0,
167 w[1].0
168 );
169 }
170 assert_eq!(collected, entries);
171 }
172}