diff options
| author | metamuffin <metamuffin@disroot.org> | 2025-12-19 21:52:59 +0100 |
|---|---|---|
| committer | metamuffin <metamuffin@disroot.org> | 2025-12-19 21:52:59 +0100 |
| commit | eac0de36221440571fe686074b04b71bf98cf727 (patch) | |
| tree | 76bad4c937e203bc13b6adcced9ed0b41432c2ae | |
| parent | da985cc06e4caa7501222dbf54f212536fd42b0c (diff) | |
| download | jellything-eac0de36221440571fe686074b04b71bf98cf727.tar jellything-eac0de36221440571fe686074b04b71bf98cf727.tar.bz2 jellything-eac0de36221440571fe686074b04b71bf98cf727.tar.zst | |
things
| -rw-r--r-- | database/src/indices/key.rs | 42 | ||||
| -rw-r--r-- | database/src/indices/mod.rs | 1 | ||||
| -rw-r--r-- | database/src/indices/order.rs | 33 | ||||
| -rw-r--r-- | database/src/iterator.rs | 70 | ||||
| -rw-r--r-- | database/src/lib.rs | 3 | ||||
| -rw-r--r-- | database/src/table.rs | 1 |
6 files changed, 134 insertions, 16 deletions
diff --git a/database/src/indices/key.rs b/database/src/indices/key.rs new file mode 100644 index 0000000..ab56f76 --- /dev/null +++ b/database/src/indices/key.rs @@ -0,0 +1,42 @@ +/* + This file is part of jellything (https://codeberg.org/metamuffin/jellything) + which is licensed under the GNU Affero General Public License (version 3); see /COPYING. + Copyright (C) 2025 metamuffin <metamuffin.org> +*/ + +use crate::{ + backends::WriteTransaction, + indices::Index, + table::{RowNum, Table, TableNum}, +}; +use anyhow::Result; + +pub struct KeyIndex<T> { + id: TableNum, + key: fn(&T) -> &[u8], +} + +impl<T: 'static> KeyIndex<T> { + pub fn new(table: &mut Table<T>, id: TableNum, key: fn(&T) -> &[u8]) -> Self { + table.indices.push(Box::new(Self { id, key })); + Self { id, key } + } + pub fn key(&self, id: RowNum, val: &T) -> Vec<u8> { + let mut v = Vec::new(); + v.extend(self.id.to_be_bytes()); + v.extend((self.key)(val)); + v.extend(id.to_be_bytes()); + v + } +} +impl<T: 'static> Index<T> for KeyIndex<T> { + fn add(&self, db: &mut dyn WriteTransaction, id: RowNum, val: &T) -> Result<()> { + db.set(&self.key(id, val), &[]) + } + fn remove(&self, db: &mut dyn WriteTransaction, id: RowNum, val: &T) -> Result<()> { + db.del(&self.key(id, val)) + } + fn compare(&self, before: &T, after: &T) -> bool { + (self.key)(before) == (self.key)(after) + } +} diff --git a/database/src/indices/mod.rs b/database/src/indices/mod.rs index 523235e..e291c91 100644 --- a/database/src/indices/mod.rs +++ b/database/src/indices/mod.rs @@ -8,6 +8,7 @@ use crate::{backends::WriteTransaction, table::RowNum}; use anyhow::Result; pub mod order; +pub mod key; pub trait Index<T> { fn add(&self, db: &mut dyn WriteTransaction, row: RowNum, val: &T) -> Result<()>; diff --git a/database/src/indices/order.rs b/database/src/indices/order.rs index 5b7924b..25ab01b 100644 --- a/database/src/indices/order.rs +++ b/database/src/indices/order.rs @@ -4,34 +4,35 @@ Copyright (C) 2025 metamuffin <metamuffin.org> */ -use crate::{backends::WriteTransaction, indices::Index, table::Table}; +use crate::{ + backends::WriteTransaction, + indices::Index, + table::{RowNum, Table, TableNum}, +}; use anyhow::Result; +use bytemuck::{NoUninit, bytes_of}; pub struct OrderIndex<T> { - id: u32, + id: TableNum, value: fn(&T) -> [u8; 8], } + +#[repr(C)] +#[derive(NoUninit, Clone, Copy)] +struct Key(TableNum, [u8; 8], RowNum); + impl<T: 'static> OrderIndex<T> { - pub fn new(table: &mut Table<T>, id: u32, value: fn(&T) -> [u8; 8]) -> Self { + pub fn new(table: &mut Table<T>, id: TableNum, value: fn(&T) -> [u8; 8]) -> Self { table.indices.push(Box::new(Self { id, value })); Self { id, value } } - fn key(&self, id: u64, val: &T) -> Vec<u8> { - let mut key = Vec::new(); - key.extend(self.id.to_be_bytes()); - key.extend((self.value)(val)); - key.extend(id.to_be_bytes()); - key - } } impl<T: 'static> Index<T> for OrderIndex<T> { - fn add(&self, db: &mut dyn WriteTransaction, id: u64, val: &T) -> Result<()> { - db.set(&self.key(id, val), &[])?; - Ok(()) + fn add(&self, db: &mut dyn WriteTransaction, id: RowNum, val: &T) -> Result<()> { + db.set(bytes_of(&Key(self.id, (self.value)(val), id)), &[]) } - fn remove(&self, db: &mut dyn WriteTransaction, id: u64, val: &T) -> Result<()> { - db.del(&self.key(id, val))?; - Ok(()) + fn remove(&self, db: &mut dyn WriteTransaction, id: RowNum, val: &T) -> Result<()> { + db.del(bytes_of(&Key(self.id, (self.value)(val), id))) } fn compare(&self, before: &T, after: &T) -> bool { (self.value)(before) == (self.value)(after) diff --git a/database/src/iterator.rs b/database/src/iterator.rs new file mode 100644 index 0000000..2db349b --- /dev/null +++ b/database/src/iterator.rs @@ -0,0 +1,70 @@ +/* + This file is part of jellything (https://codeberg.org/metamuffin/jellything) + which is licensed under the GNU Affero General Public License (version 3); see /COPYING. + Copyright (C) 2025 metamuffin <metamuffin.org> +*/ + +use crate::backends::ReadTransaction; +use anyhow::Result; +use std::{borrow::Cow, ops::Range}; + +pub struct PrefixIterator<'a> { + db: &'a dyn ReadTransaction, + prefix: &'a [u8], + cursor: Cow<'a, [u8]>, +} +impl Iterator for PrefixIterator<'_> { + type Item = Result<Vec<u8>>; + fn next(&mut self) -> Option<Self::Item> { + match self.db.next(&self.cursor) { + Err(e) => Some(Err(e)), + Ok(None) => None, + Ok(Some(next)) => { + if next.starts_with(self.prefix) { + self.cursor = next.clone().into(); + Some(Ok(next)) + } else { + None + } + } + } + } +} + +pub struct RangeIterator<'a> { + db: &'a dyn ReadTransaction, + range: Range<Cow<'a, [u8]>>, +} +impl Iterator for RangeIterator<'_> { + type Item = Result<Vec<u8>>; + fn next(&mut self) -> Option<Self::Item> { + match self.db.next(&self.range.start) { + Err(e) => Some(Err(e)), + Ok(None) => None, + Ok(Some(next)) => { + if next.as_slice() < self.range.end.as_ref() { + self.range.start = next.clone().into(); + Some(Ok(next)) + } else { + None + } + } + } + } +} +impl DoubleEndedIterator for RangeIterator<'_> { + fn next_back(&mut self) -> Option<Self::Item> { + match self.db.prev(&self.range.end) { + Err(e) => Some(Err(e)), + Ok(None) => None, + Ok(Some(prev)) => { + if prev.as_slice() >= self.range.start.as_ref() { + self.range.end = prev.clone().into(); + Some(Ok(prev)) + } else { + None + } + } + } + } +} diff --git a/database/src/lib.rs b/database/src/lib.rs index 6c70e51..87baae1 100644 --- a/database/src/lib.rs +++ b/database/src/lib.rs @@ -6,3 +6,6 @@ pub mod backends; pub mod indices; pub mod table; +pub mod iterator; + +pub type Pad32 = u32; diff --git a/database/src/table.rs b/database/src/table.rs index e2f6196..1f44571 100644 --- a/database/src/table.rs +++ b/database/src/table.rs @@ -11,6 +11,7 @@ use crate::{ use anyhow::Result; use serde::{Serialize, de::DeserializeOwned}; +pub type TableNum = u64; pub type RowNum = u64; pub struct Table<T> { |