aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormetamuffin <metamuffin@disroot.org>2025-12-19 21:52:59 +0100
committermetamuffin <metamuffin@disroot.org>2025-12-19 21:52:59 +0100
commiteac0de36221440571fe686074b04b71bf98cf727 (patch)
tree76bad4c937e203bc13b6adcced9ed0b41432c2ae
parentda985cc06e4caa7501222dbf54f212536fd42b0c (diff)
downloadjellything-eac0de36221440571fe686074b04b71bf98cf727.tar
jellything-eac0de36221440571fe686074b04b71bf98cf727.tar.bz2
jellything-eac0de36221440571fe686074b04b71bf98cf727.tar.zst
things
-rw-r--r--database/src/indices/key.rs42
-rw-r--r--database/src/indices/mod.rs1
-rw-r--r--database/src/indices/order.rs33
-rw-r--r--database/src/iterator.rs70
-rw-r--r--database/src/lib.rs3
-rw-r--r--database/src/table.rs1
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> {