From 8ddc953db535823be98a64e5fd7a5472df888949 Mon Sep 17 00:00:00 2001 From: "Aode (lion)" Date: Fri, 11 Mar 2022 19:26:32 -0600 Subject: [PATCH] Ayy lmao --- .gitignore | 3 + Cargo.toml | 9 ++ examples/demo.rs | 34 +++++++ src/lib.rs | 226 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 272 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 examples/demo.rs create mode 100644 src/lib.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4c62a89 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/target +Cargo.lock +db.persy diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..ed96d7d --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "persy-trees" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +persy = "1.2" diff --git a/examples/demo.rs b/examples/demo.rs new file mode 100644 index 0000000..a6bddd0 --- /dev/null +++ b/examples/demo.rs @@ -0,0 +1,34 @@ +use persy::ByteVec; +use persy_trees::{Db, Tree}; + +fn main() -> Result<(), Box> { + let db = Db::open("./db.persy")?; + + let tree: Tree = db.open_tree("some-tree-name")?; + + let mut tx1 = tree.transaction()?; + let mut tx2 = tree.transaction()?; + + let put: ByteVec = vec![0, 1, 2, 3, 4].into(); + + tx1.insert("howdy".into(), put.clone())?; + tx2.insert("meowdy".into(), put.clone())?; + + let got1 = tx1.get(&"howdy".into())?.expect("We just inserted this"); + let got2 = tx2.get(&"meowdy".into())?.expect("We just inserted this"); + + assert_eq!(got1, put); + assert_eq!(got2, put); + + for (k, v) in tx1.range(..)? { + println!("{}: {:?}", k, &*v); + } + for (k, v) in tx2.range(..)? { + println!("{}: {:?}", k, &*v); + } + + tx1.commit()?; + tx2.commit()?; + + Ok(()) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..0aad720 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,226 @@ +use persy::{Config, IndexId, IndexType, Persy, PersyError, SegmentId, TxIndexIter, ValueMode, PE}; +use std::marker::PhantomData; +use std::ops::RangeBounds; +use std::path::Path; + +#[derive(Debug)] +pub struct Error { + kind: ErrorKind, +} + +#[derive(Debug)] +pub enum ErrorKind { + Persy(PersyError), +} + +#[derive(Clone)] +pub struct Db { + persy: Persy, +} + +pub struct Tree { + name: String, + _segment_id: SegmentId, + _index_id: IndexId, + + persy: Persy, + + _key: PhantomData, + _value: PhantomData, +} + +pub struct Transaction<'a, K, V> { + tree: &'a Tree, + tx: persy::Transaction, +} + +pub struct Iter<'a, K: IndexType, V: IndexType> { + iter: TxIndexIter<'a, K, V>, +} + +impl Db { + pub fn open(path: impl AsRef) -> Result { + let persy = Persy::open_or_create_with(path, Config::new(), |_| Ok(()))?; + Ok(Self { persy }) + } + + pub fn open_tree(&self, tree_name: N) -> Result, Error> + where + K: IndexType, + V: IndexType, + N: Into, + { + let segment_id; + let index_id; + + let name = tree_name.into(); + + let mut tx = self.persy.begin()?; + + if tx.exists_segment(&name)? { + segment_id = tx.solve_segment_id(&name)?; + index_id = tx.solve_index_id(&name)?; + } else { + segment_id = tx.create_segment(&name)?; + tx.create_index::(&name, ValueMode::Replace)?; + index_id = tx.solve_index_id(&name)?; + } + let tx = tx.prepare()?; + tx.commit()?; + + Ok(Tree { + name, + _segment_id: segment_id, + _index_id: index_id, + + persy: self.persy.clone(), + + _key: PhantomData, + _value: PhantomData, + }) + } +} + +impl Tree { + pub fn transaction(&self) -> Result, Error> { + let tx = self.persy.begin()?; + + Ok(Transaction { tree: self, tx }) + } +} + +impl<'a, K, V> Transaction<'a, K, V> +where + K: IndexType, + V: IndexType, +{ + pub fn get(&mut self, key: &K) -> Result, Error> { + Ok(self.tx.one(&self.tree.name, key)?) + } + + pub fn range>(&mut self, range: R) -> Result, Error> { + Ok(Iter::new(self.tx.range(&self.tree.name, range)?)) + } + + pub fn insert(&mut self, key: K, value: V) -> Result<(), Error> { + self.tx.put(&self.tree.name, key, value)?; + Ok(()) + } + + pub fn remove(&mut self, key: K) -> Result<(), Error> { + self.tx.remove(&self.tree.name, key, None as Option)?; + Ok(()) + } + + pub fn commit(self) -> Result<(), Error> { + self.tx.prepare()?.commit()?; + Ok(()) + } + + pub fn rollback(self) -> Result<(), Error> { + self.tx.rollback()?; + Ok(()) + } +} + +impl<'a, K, V> Iter<'a, K, V> +where + K: IndexType, + V: IndexType, +{ + fn new(iter: TxIndexIter<'a, K, V>) -> Self { + Self { iter } + } +} + +impl<'a, K, V> Iterator for Iter<'a, K, V> +where + K: IndexType, + V: IndexType, +{ + type Item = (K, V); + + fn next(&mut self) -> Option { + loop { + let (key, mut values) = self.iter.next()?; + + if let Some(value) = values.next() { + return Some((key, value)); + } + } + } +} + +impl<'a, K, V> DoubleEndedIterator for Iter<'a, K, V> +where + K: IndexType, + V: IndexType, +{ + fn next_back(&mut self) -> Option { + loop { + let (key, mut values) = self.iter.next_back()?; + + if let Some(value) = values.next() { + return Some((key, value)); + } + } + } +} + +impl Clone for Tree { + fn clone(&self) -> Self { + Self { + name: self.name.clone(), + _segment_id: self._segment_id, + _index_id: self._index_id.clone(), + + persy: self.persy.clone(), + + _key: PhantomData, + _value: PhantomData, + } + } +} + +impl> From> for ErrorKind { + fn from(e: PE) -> Self { + ErrorKind::Persy(e.persy_error()) + } +} + +impl From for Error +where + ErrorKind: From, +{ + fn from(e: T) -> Self { + ErrorKind::from(e).into() + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + std::fmt::Display::fmt(&self.kind, f) + } +} + +impl std::error::Error for Error { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + self.kind.source() + } +} + +impl std::fmt::Display for ErrorKind { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Self::Persy(_) => write!(f, "Error in storage engine"), + } + } +} + +impl std::error::Error for ErrorKind { + fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { + match self { + Self::Persy(ref err) => Some(err), + } + } +}