]> git.mikk.net Git - mtbl-rs/commitdiff
WIP commit: attempt to make Source object safe
authorChris Mikkelson <cmikk@fsi.io>
Fri, 19 Jul 2024 17:10:19 +0000 (12:10 -0500)
committerChris Mikkelson <cmikk@fsi.io>
Fri, 19 Jul 2024 17:10:19 +0000 (12:10 -0500)
Use associated iterator types instead of `impl Iter`. Move
get, get_prefix, get_range to separate "Ranges" trait, with
a generic default implementation based on iter() enabled by
"DefaultRanges" trait.

WIP due to one pesky lifetime issue.

src/merger.rs
src/source.rs

index a7d671e26f161119f54c1d5c26577f85c728d2ad..78e036266508a932b0da510781f9ad96f627e5f0 100644 (file)
@@ -1,4 +1,4 @@
-use crate::{Entry, Iter, Source};
+use crate::{source::Ranges, Entry, Iter, Source};
 use std::cmp::Ordering;
 use std::collections::BinaryHeap;
 
@@ -42,7 +42,7 @@ impl<I: Iter> Ord for MergeEntry<I> {
     }
 }
 
-struct MergeIter<I: Iter> {
+pub struct MergeIter<I: Iter> {
     heap: BinaryHeap<MergeEntry<I>>,
     finished: Vec<I>,
     last_key: Vec<u8>,
@@ -145,19 +145,26 @@ impl<I: Iter> Iter for MergeIter<I> {
 }
 
 impl<S: Source> Source for Merger<S> {
-    fn iter(&self) -> impl Iter {
+    type It = MergeIter<S::It>;
+    fn iter(&self) -> Self::It {
         MergeIter::from(self.sources.iter().map(|s| s.iter()))
     }
+}
+
+impl<S: Source + Ranges> Ranges for Merger<S> {
+    type Get = MergeIter<<S as Ranges>::Get>;
+    type Prefix = MergeIter<<S as Ranges>::Prefix>;
+    type Range = MergeIter<<S as Ranges>::Range>;
 
-    fn get(&self, key: &[u8]) -> impl Iter {
+    fn get(&self, key: &[u8]) -> Self::Get {
         MergeIter::from(self.sources.iter().map(|s| s.get(key)))
     }
 
-    fn get_prefix(&self, prefix: &[u8]) -> impl Iter {
+    fn get_prefix(&self, prefix: &[u8]) -> Self::Prefix {
         MergeIter::from(self.sources.iter().map(|s| s.get_prefix(prefix)))
     }
 
-    fn get_range(&self, start: &[u8], end: &[u8]) -> impl Iter {
+    fn get_range(&self, start: &[u8], end: &[u8]) -> Self::Range {
         MergeIter::from(self.sources.iter().map(|s| s.get_range(start, end)))
     }
 }
@@ -167,15 +174,17 @@ mod test {
     use super::Merger;
     use crate::source::test::TestSource;
     use crate::{Entry, Source};
+    use std::marker::PhantomData;
 
     fn tnum(m: u8) -> Vec<u8> {
         Vec::from_iter((1u8..255).into_iter().filter(|i| i % m == 0))
     }
 
-    fn test_source(m: u8) -> TestSource {
-        TestSource(Vec::from_iter(
-            tnum(m).into_iter().map(|n| Entry::new(vec![n], vec![0])),
-        ))
+    fn test_source<'a>(m: u8) -> TestSource<'a> {
+        TestSource(
+            Vec::from_iter(tnum(m).into_iter().map(|n| Entry::new(vec![n], vec![0]))),
+            PhantomData,
+        )
     }
 
     #[test]
index 0bb74a6c131a703b2f306c79611ed25f81368833..1f7ce310ffa60844dab049e2d5087728c1e6329e 100644 (file)
@@ -5,25 +5,43 @@ pub trait Iter: Iterator<Item = Entry> {
     fn seek(&mut self, key: &[u8]);
 }
 
-impl<'a> Iter for Box<dyn Iter + 'a> {
+impl Iter for Box<dyn Iter> {
     fn seek(&mut self, key: &[u8]) {
         self.as_mut().seek(key);
     }
 }
 
 pub trait Source {
-    fn iter(&self) -> impl Iter;
+    type It: Iter;
+    fn iter(&self) -> <Self as Source>::It;
+}
+pub trait DefaultRanges {}
+pub trait Ranges {
+    type Get: Iter;
+    type Prefix: Iter;
+    type Range: Iter;
+
+    fn get(&self, key: &[u8]) -> Self::Get;
+    fn get_prefix(&self, prefix: &[u8]) -> Self::Prefix;
+    fn get_range(&self, start: &[u8], end: &[u8]) -> Self::Range;
+}
 
-    fn get(&self, key: &[u8]) -> impl Iter {
+impl<S: Source + DefaultRanges> Ranges for S {
+    type Get = RangeIter<<S as Source>::It>;
+    type Prefix = PrefixIter<<S as Source>::It>;
+    type Range = RangeIter<<S as Source>::It>;
+
+    fn get(&self, key: &[u8]) -> Self::Get {
         let mut res = RangeIter {
             iter: self.iter(),
+            start: Vec::from(key),
             end: Vec::from(key),
         };
         res.seek(key);
         res
     }
 
-    fn get_prefix(&self, prefix: &[u8]) -> impl Iter {
+    fn get_prefix(&self, prefix: &[u8]) -> Self::Prefix {
         let mut res = PrefixIter {
             iter: self.iter(),
             prefix: Vec::from(prefix),
@@ -32,9 +50,10 @@ pub trait Source {
         res
     }
 
-    fn get_range(&self, start: &[u8], end: &[u8]) -> impl Iter {
+    fn get_range(&self, start: &[u8], end: &[u8]) -> Self::Range {
         let mut res = RangeIter {
             iter: self.iter(),
+            start: Vec::from(start),
             end: Vec::from(end),
         };
         res.seek(start);
@@ -42,7 +61,7 @@ pub trait Source {
     }
 }
 
-struct PrefixIter<I: Iter> {
+pub struct PrefixIter<I: Iter> {
     iter: I,
     prefix: Vec<u8>,
 }
@@ -65,8 +84,9 @@ impl<I: Iter> Iter for PrefixIter<I> {
     }
 }
 
-struct RangeIter<I: Iter> {
+pub struct RangeIter<I: Iter> {
     iter: I,
+    start: Vec<u8>,
     end: Vec<u8>,
 }
 
@@ -84,18 +104,26 @@ impl<I: Iter> Iterator for RangeIter<I> {
 
 impl<I: Iter> Iter for RangeIter<I> {
     fn seek(&mut self, key: &[u8]) {
-        self.iter.seek(key);
+        if key <= self.start.as_slice() {
+            self.iter.seek(self.start.as_slice());
+        } else if key > self.end.as_slice() {
+            self.iter.seek(self.end.as_slice());
+            self.iter.next();
+        } else {
+            self.iter.seek(key);
+        }
     }
 }
 
 #[cfg(test)]
 pub mod test {
-    use super::{Entry, Iter, Source};
+    use super::{DefaultRanges, Entry, Iter, Ranges, Source};
+    use std::marker::PhantomData;
 
-    pub struct TestSource(pub Vec<Entry>);
+    pub struct TestSource<'a>(pub Vec<Entry>, pub PhantomData<&'a u8>);
 
     struct TestIter<'a> {
-        source: &'a TestSource,
+        source: &'a TestSource<'a>,
         off: usize,
     }
 
@@ -122,23 +150,29 @@ pub mod test {
         }
     }
 
-    impl Source for TestSource {
-        fn iter(&self) -> impl Iter {
+    impl<'a> Source for TestSource<'a> {
+        type It = TestIter<'a>;
+
+        fn iter(&self) -> TestIter<'a> {
             TestIter {
                 source: self,
                 off: 0,
             }
         }
     }
-
-    fn test_source() -> TestSource {
-        TestSource(vec![
-            Entry::new(vec![0, 0, 0, 0], vec![0]),
-            Entry::new(vec![0, 0, 0, 1], vec![1]),
-            Entry::new(vec![0, 0, 1, 0], vec![2]),
-            Entry::new(vec![0, 1, 0, 0], vec![3]),
-            Entry::new(vec![1, 0, 0, 0], vec![4]),
-        ])
+    impl<'a> DefaultRanges for TestSource<'a> {}
+
+    fn test_source<'a>() -> TestSource<'a> {
+        TestSource(
+            vec![
+                Entry::new(vec![0, 0, 0, 0], vec![0]),
+                Entry::new(vec![0, 0, 0, 1], vec![1]),
+                Entry::new(vec![0, 0, 1, 0], vec![2]),
+                Entry::new(vec![0, 1, 0, 0], vec![3]),
+                Entry::new(vec![1, 0, 0, 0], vec![4]),
+            ],
+            PhantomData,
+        )
     }
 
     #[test]