1use super::PageRange;
2use crate::digest::PageDigest;
3
4#[derive(Debug, Clone, PartialEq)]
37pub struct PageRangeSnapshot<K>(Vec<OwnedPageRange<K>>);
38
39impl<K> PageRangeSnapshot<K> {
40 pub fn iter(&self) -> impl ExactSizeIterator<Item = PageRange<'_, K>>
42 where
43 K: PartialOrd,
44 {
45 self.0
46 .iter()
47 .map(|v| PageRange::new(&v.start, &v.end, v.hash.clone()))
48 }
49}
50
51impl<'a, K> From<Vec<PageRange<'a, K>>> for PageRangeSnapshot<K>
52where
53 K: Clone,
54{
55 fn from(value: Vec<PageRange<'a, K>>) -> Self {
56 value.into_iter().collect()
57 }
58}
59
60impl<'a, K> FromIterator<PageRange<'a, K>> for PageRangeSnapshot<K>
61where
62 K: Clone + 'a,
63{
64 fn from_iter<T: IntoIterator<Item = PageRange<'a, K>>>(iter: T) -> Self {
65 Self(iter.into_iter().map(OwnedPageRange::from).collect())
66 }
67}
68
69impl<K> From<Vec<OwnedPageRange<K>>> for PageRangeSnapshot<K> {
70 fn from(value: Vec<OwnedPageRange<K>>) -> Self {
71 value.into_iter().collect()
72 }
73}
74
75impl<K> FromIterator<OwnedPageRange<K>> for PageRangeSnapshot<K> {
76 fn from_iter<T: IntoIterator<Item = OwnedPageRange<K>>>(iter: T) -> Self {
77 Self(iter.into_iter().map(OwnedPageRange::from).collect())
78 }
79}
80
81#[derive(Debug, Clone, PartialEq, Eq)]
87pub struct OwnedPageRange<K> {
88 start: K,
89 end: K,
90 hash: PageDigest,
91}
92
93impl<K> OwnedPageRange<K>
94where
95 K: PartialOrd,
96{
97 pub fn new(start: K, end: K, hash: PageDigest) -> Self {
104 assert!(start <= end);
105 Self { start, end, hash }
106 }
107}
108
109impl<'a, K> From<PageRange<'a, K>> for OwnedPageRange<K>
110where
111 K: Clone,
112{
113 fn from(v: PageRange<'a, K>) -> Self {
114 Self {
115 start: v.start().clone(),
116 end: v.end().clone(),
117 hash: v.into_hash(),
118 }
119 }
120}
121
122#[cfg(test)]
123mod tests {
124 use assert_matches::assert_matches;
125
126 use super::*;
127 use crate::{diff::diff, MerkleSearchTree};
128
129 #[test]
130 fn test_owned_usage() {
131 let mut a = MerkleSearchTree::default();
132 let mut b = MerkleSearchTree::default();
133
134 a.upsert("bananas", &42);
135 b.upsert("bananas", &24);
136
137 let _ = a.root_hash();
139 let _ = b.root_hash();
140
141 let snap_a = PageRangeSnapshot::from(a.serialise_page_ranges().unwrap());
143 let snap_b = PageRangeSnapshot::from(b.serialise_page_ranges().unwrap());
144
145 a.upsert("bananas", &13);
147 b.upsert("bananas", &13);
148
149 assert_matches!(diff(snap_a.iter(), snap_b.iter()).as_slice(), [range] => {
152 assert_eq!(range.start(), &"bananas");
153 assert_eq!(range.end(), &"bananas");
154 });
155 }
156
157 #[test]
158 fn test_collect_equivalence_refs() {
159 let a1 = vec![
160 PageRange::new(
161 &"a",
162 &"b",
163 PageDigest::new([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]),
164 ),
165 PageRange::new(
166 &"c",
167 &"d",
168 PageDigest::new([2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]),
169 ),
170 ];
171
172 let a2 = a1.clone().into_iter().collect::<PageRangeSnapshot<_>>();
173 let a1 = PageRangeSnapshot::from(a1);
174
175 assert_eq!(a1, a2)
176 }
177
178 #[test]
179 fn test_collect_equivalence_owned() {
180 let a1 = vec![
181 OwnedPageRange::new(
182 "a",
183 "b",
184 PageDigest::new([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]),
185 ),
186 OwnedPageRange::new(
187 "c",
188 "d",
189 PageDigest::new([2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]),
190 ),
191 ];
192
193 let a2 = a1.clone().into_iter().collect::<PageRangeSnapshot<_>>();
194 let a1 = PageRangeSnapshot::from(a1);
195
196 assert_eq!(a1, a2)
197 }
198
199 #[test]
200 fn test_owned_ref_page_equivalence() {
201 let ref_pages = [
202 PageRange::new(
203 &"a",
204 &"b",
205 PageDigest::new([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]),
206 ),
207 PageRange::new(
208 &"c",
209 &"d",
210 PageDigest::new([2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]),
211 ),
212 ];
213
214 let owned_pages = [
215 OwnedPageRange::new(
216 "a",
217 "b",
218 PageDigest::new([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]),
219 ),
220 OwnedPageRange::new(
221 "c",
222 "d",
223 PageDigest::new([2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]),
224 ),
225 ];
226
227 let ref_pages = ref_pages.into_iter().collect::<PageRangeSnapshot<_>>();
228 let owned_pages = owned_pages.into_iter().collect::<PageRangeSnapshot<_>>();
229
230 assert_eq!(ref_pages, owned_pages);
231 }
232
233 #[test]
234 fn test_exact_size_iter() {
235 let pages = [
236 PageRange::new(
237 &"a",
238 &"b",
239 PageDigest::new([1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]),
240 ),
241 PageRange::new(
242 &"c",
243 &"d",
244 PageDigest::new([2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2]),
245 ),
246 ];
247
248 let pages = pages.into_iter().collect::<PageRangeSnapshot<_>>();
249 assert_eq!(pages.iter().len(), 2);
250 }
251}