]> git.mikk.net Git - mtbl-rs/commitdiff
Initial commit
authorChris Mikkelson <cmikk@fsi.io>
Sun, 7 Apr 2024 16:56:05 +0000 (11:56 -0500)
committerChris Mikkelson <cmikk@fsi.io>
Sun, 7 Apr 2024 16:56:05 +0000 (11:56 -0500)
.gitignore [new file with mode: 0644]
Cargo.lock [new file with mode: 0644]
Cargo.toml [new file with mode: 0644]
src/bin/mtbl_dump.rs [new file with mode: 0644]
src/bin/mtbl_info.rs [new file with mode: 0644]
src/bin/mtbl_merge.rs [new file with mode: 0644]
src/bin/mtbl_verify.rs [new file with mode: 0644]
src/entry.rs [new file with mode: 0644]
src/iter.rs [new file with mode: 0644]
src/lib.rs [new file with mode: 0644]
tests/entry.rs [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..ea8c4bf
--- /dev/null
@@ -0,0 +1 @@
+/target
diff --git a/Cargo.lock b/Cargo.lock
new file mode 100644 (file)
index 0000000..457e834
--- /dev/null
@@ -0,0 +1,65 @@
+# This file is automatically @generated by Cargo.
+# It is not intended for manual editing.
+version = 3
+
+[[package]]
+name = "lender"
+version = "0.2.9"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "39b1f7f753a5da003547d93e9e8f6542e81db06adad15dda47a9cd12559ab2e0"
+dependencies = [
+ "lender-derive",
+]
+
+[[package]]
+name = "lender-derive"
+version = "0.1.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "556faf0c9adb22669a5f9f6b4ed804c8048d205dcd00fadd463affbb02931d26"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn",
+]
+
+[[package]]
+name = "mtbl"
+version = "0.1.0"
+dependencies = [
+ "lender",
+]
+
+[[package]]
+name = "proc-macro2"
+version = "1.0.79"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
+dependencies = [
+ "unicode-ident",
+]
+
+[[package]]
+name = "quote"
+version = "1.0.35"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "291ec9ab5efd934aaf503a6466c5d5251535d108ee747472c3977cc5acc868ef"
+dependencies = [
+ "proc-macro2",
+]
+
+[[package]]
+name = "syn"
+version = "2.0.57"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "11a6ae1e52eb25aab8f3fb9fca13be982a373b8f1157ca14b897a825ba4a2d35"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
+[[package]]
+name = "unicode-ident"
+version = "1.0.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b"
diff --git a/Cargo.toml b/Cargo.toml
new file mode 100644 (file)
index 0000000..66ae1c3
--- /dev/null
@@ -0,0 +1,9 @@
+[package]
+name = "mtbl"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+lender = "0.2.9"
diff --git a/src/bin/mtbl_dump.rs b/src/bin/mtbl_dump.rs
new file mode 100644 (file)
index 0000000..e7a11a9
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/bin/mtbl_info.rs b/src/bin/mtbl_info.rs
new file mode 100644 (file)
index 0000000..e7a11a9
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/bin/mtbl_merge.rs b/src/bin/mtbl_merge.rs
new file mode 100644 (file)
index 0000000..e7a11a9
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/bin/mtbl_verify.rs b/src/bin/mtbl_verify.rs
new file mode 100644 (file)
index 0000000..e7a11a9
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/src/entry.rs b/src/entry.rs
new file mode 100644 (file)
index 0000000..23088fa
--- /dev/null
@@ -0,0 +1,89 @@
+use std::cmp::Ordering;
+pub use std::rc::Rc;
+
+#[derive(Debug, Clone)]
+pub struct Entry {
+    pub key: Rc<Vec<u8>>,
+    pub value: Rc<Vec<u8>>,
+}
+
+impl Entry {
+    pub fn new() -> Entry {
+        Entry {
+            key: Rc::new(Vec::new()),
+            value: Rc::new(Vec::new()),
+        }
+    }
+    pub fn from_key_value<K: AsRef<[u8]>, V: AsRef<[u8]>>(k: K, v: V) -> Entry {
+        let mut key = Vec::<u8>::with_capacity(k.as_ref().len());
+        let mut value = Vec::<u8>::with_capacity(v.as_ref().len());
+
+        key.extend_from_slice(k.as_ref());
+        value.extend_from_slice(v.as_ref());
+
+        Entry {
+            key: Rc::new(key),
+            value: Rc::new(value),
+        }
+    }
+
+    pub fn unpack(&self) -> (&[u8], &[u8]) {
+        (self.key.as_slice(), self.value.as_slice())
+    }
+}
+
+// Entries are ordered and compared by key only
+impl PartialOrd for Entry {
+    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
+        self.key.partial_cmp(&other.key)
+    }
+}
+
+impl PartialEq for Entry {
+    fn eq(&self, other: &Self) -> bool {
+        self.key == other.key
+    }
+}
+
+#[cfg(test)]
+mod test {
+
+    use crate::*;
+
+    struct TestIter(Entry);
+
+    impl TestIter {
+        fn new() -> TestIter {
+            TestIter(Entry::new())
+        }
+    }
+
+    impl Iterator for TestIter {
+        type Item = Entry;
+
+        fn next(&mut self) -> Option<Entry> {
+            println!("key strong_count = {}", Rc::strong_count(&self.0.key));
+            Rc::make_mut(&mut self.0.key).push(0);
+            Some(self.0.clone())
+        }
+    }
+
+    #[test]
+    fn test_iter() {
+        for e in TestIter::new() {
+            if e.key.len() > 3 {
+                break;
+            }
+        }
+    }
+
+    #[test]
+    fn test_iter_filter() {
+        for e in TestIter::new().filter(|x: &Entry| x.key.len() % 2 == 0) {
+            println!("{:?}", e);
+            if e.key.len() > 6 {
+                break;
+            }
+        }
+    }
+}
diff --git a/src/iter.rs b/src/iter.rs
new file mode 100644 (file)
index 0000000..5c4ab88
--- /dev/null
@@ -0,0 +1,182 @@
+use crate::entry::Entry;
+use std::cell::RefCell;
+use std::iter::Iterator;
+use std::rc::Rc;
+
+pub trait Iter: Iterator<Item = Entry> + Sized {
+    fn seek<T: AsRef<[u8]>>(&mut self, key: T);
+
+    fn wrap_iter<F: FnOnce(IterBox<Self>) -> O, O: Iterator<Item=Entry>>(self, f: F) -> impl Iter
+    {
+        let it = IterBox::new(self);
+        WrapIter {
+            inner: it.clone(),
+            outer: f(it),
+        }
+    }
+
+    // provided methods
+    fn filter_seek<F>(&mut self, filter: F) -> impl Iter
+    where
+        F: FnMut(&Entry, &mut Vec<u8>) -> FilterSeekResult,
+    {
+        FilterSeek {
+            inner: self,
+            filter_func: filter,
+            seek_key: Vec::new(),
+        }
+    }
+}
+
+// WrapIter
+
+pub struct IterBox<I: Iter>(Rc<RefCell<I>>);
+
+impl<I: Iter> Clone for IterBox<I> {
+    fn clone(&self) -> Self {
+        IterBox(self.0.clone())
+    }
+}
+
+impl<I: Iter> IterBox<I> {
+    fn new(i: I) -> IterBox<I> {
+        IterBox(Rc::new(RefCell::new(i)))
+    }
+}
+
+impl<I: Iter> Iterator for IterBox<I> {
+    type Item = Entry;
+
+    fn next(&mut self) -> Option<Entry> {
+        self.0.borrow_mut().next()
+    }
+}
+
+impl<I: Iter> Iter for IterBox<I> {
+    fn seek<T: AsRef<[u8]>>(&mut self, key: T) {
+        self.0.borrow_mut().seek(key);
+    }
+}
+
+struct WrapIter<I: Iter, O: Iterator<Item = Entry>> {
+    inner: IterBox<I>,
+    outer: O,
+}
+
+impl<I: Iter, O: Iterator<Item = Entry>> Iterator for WrapIter<I, O> {
+    type Item = Entry;
+
+    fn next(&mut self) -> Option<Self::Item> {
+        self.outer.next()
+    }
+}
+
+impl<I: Iter, O: Iterator<Item = Entry>> Iter for WrapIter<I, O> {
+    fn seek<T: AsRef<[u8]>>(&mut self, key: T) {
+        self.inner.seek(key)
+    }
+}
+
+// FilterSeek
+
+pub enum FilterSeekResult {
+    Keep,
+    Skip,
+    Seek,
+}
+pub use FilterSeekResult::*;
+
+struct FilterSeek<'i, I: Iterator<Item = Entry>, F: FnMut(&Entry, &mut Vec<u8>) -> FilterSeekResult>
+{
+    inner: &'i mut I,
+    filter_func: F,
+    seek_key: Vec<u8>,
+}
+
+impl<'i, I, F> Iterator for FilterSeek<'i, I, F>
+where
+    F: FnMut(&Entry, &mut Vec<u8>) -> FilterSeekResult,
+    I: Iter<Item = Entry>,
+{
+    type Item = Entry;
+
+    fn next(&mut self) -> Option<Entry> {
+        self.seek_key.clear();
+        while let Some(e) = self.inner.next() {
+            match (self.filter_func)(&e, &mut self.seek_key) {
+                Skip => continue,
+                Keep => return Some(e),
+                Seek => self.inner.seek(self.seek_key.as_slice()),
+            }
+        }
+        None
+    }
+}
+
+impl<'i, I, F> Iter for FilterSeek<'i, I, F>
+where
+    F: FnMut(&Entry, &mut Vec<u8>) -> FilterSeekResult,
+    I: Iter<Item = Entry>,
+{
+    fn seek<T: AsRef<[u8]>>(&mut self, key: T) {
+        self.inner.seek(key.as_ref());
+    }
+}
+
+#[cfg(test)]
+mod test {
+    use super::*;
+
+    struct TestIter(u8);
+
+    impl Iterator for TestIter {
+        type Item = Entry;
+
+        fn next(&mut self) -> Option<Entry> {
+            match self.0 {
+                255 => None,
+                _ => {
+                    let res = Entry::from_key_value(vec![self.0], vec![self.0]);
+                    self.0 = self.0 + 1;
+                    Some(res)
+                }
+            }
+        }
+    }
+
+    impl Iter for TestIter {
+        fn seek<T: AsRef<[u8]>>(&mut self, kr: T) {
+            self.0 = kr.as_ref()[0];
+        }
+    }
+
+    #[test]
+    fn test_iter_filter() {
+        let mut ti = TestIter(0);
+        let v: Vec<Entry> = ti
+            .filter_seek(|e, k| {
+                let b = e.key[0];
+                if b % 2 > 0 {
+                    if b < 60 {
+                        k.push((b + 1) * 4);
+                        return FilterSeekResult::Seek;
+                    }
+                    return FilterSeekResult::Skip;
+                }
+                FilterSeekResult::Keep
+            })
+            .filter(|e| e.key[0] % 5 == 0)
+            .collect();
+        println!("length = {}", v.len());
+        assert!(v.into_iter().all(|e| e.key[0] % 2 == 0));
+    }
+
+    #[test]
+    fn test_iter_wrap() {
+        let ti = TestIter(0);
+        let mut mi = ti.wrap_iter(|i| i.filter(|e| e.key[0] % 2 == 0));
+        mi.seek(&[100]);
+        let v: Vec<Entry> = mi.collect();
+        println!("{:?}", v);
+    }
+}
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644 (file)
index 0000000..34db328
--- /dev/null
@@ -0,0 +1,5 @@
+pub mod entry;
+pub mod iter;
+
+pub use entry::*;
+pub use iter::*;
diff --git a/tests/entry.rs b/tests/entry.rs
new file mode 100644 (file)
index 0000000..343cb68
--- /dev/null
@@ -0,0 +1,9 @@
+use mtbl;
+
+#[test]
+fn from_key_value() {
+    let e = mtbl::Entry::from_key_value(vec![0u8, 1, 2, 3], vec![4u8, 5, 6, 7]);
+    println!("{:?}", e);
+    let (k, v) = e.unpack();
+    println!("{:?}", (k, v));
+}