/* 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 */ use crate::backends::{Db, ReadTransaction, ReadTxnFunction, WriteTransaction, WriteTxnFunction}; use anyhow::Result; use redb::{AccessGuard, Database, ReadableDatabase, ReadableTable, StorageError, TableDefinition}; use std::path::Path; pub struct Redb { db: Database, } const TABLE: TableDefinition<&[u8], &[u8]> = TableDefinition::new("kv"); impl Redb { pub fn new(path: &Path) -> Result { Ok(Self { db: Database::create(path)?, }) } } impl Db for Redb { fn write_transaction(&self, f: &mut WriteTxnFunction) -> Result<()> { let mut txn = self.db.begin_write()?; f(&mut txn)?; txn.commit()?; Ok(()) } fn read_transaction(&self, f: &mut ReadTxnFunction) -> Result<()> { let mut txn = self.db.begin_read()?; f(&mut txn)?; Ok(()) } } impl WriteTransaction for redb::WriteTransaction { fn set(&mut self, key: &[u8], value: &[u8]) -> Result<()> { self.open_table(TABLE)?.insert(key, value)?; Ok(()) } fn del(&mut self, key: &[u8]) -> Result<()> { self.open_table(TABLE)?.remove(key)?; Ok(()) } } impl ReadTransaction for redb::WriteTransaction { fn get<'a>(&'a self, key: &[u8]) -> Result>> { match self.open_table(TABLE)?.get(key)? { Some(v) => Ok(Some(v.value().to_vec())), None => Ok(None), } } fn iter<'a>( &'a self, key: &[u8], reverse: bool, ) -> Result>> + 'a>> { // let k = |e: Result<(AccessGuard<'_, &[u8]>, AccessGuard<'_, &[u8]>), StorageError>| { // e.map(|e| e.0.value().to_vec()).map_err(|e| e.into()) // }; // Ok(if reverse { // Box::new(self.open_table(TABLE)?.range(..=key)?.rev().map(k)) // } else { // Box::new(self.open_table(TABLE)?.range(key..)?.map(k)) // }) todo!() } } impl ReadTransaction for redb::ReadTransaction { fn get<'a>(&'a self, key: &[u8]) -> Result>> { match self.open_table(TABLE)?.get(key)? { Some(v) => Ok(Some(v.value().to_vec())), None => Ok(None), } } fn iter<'a>( &'a self, key: &[u8], reverse: bool, ) -> Result>> + 'a>> { let k = |e: Result<(AccessGuard<'_, &[u8]>, AccessGuard<'_, &[u8]>), StorageError>| { e.map(|e| e.0.value().to_vec()).map_err(|e| e.into()) }; Ok(if reverse { Box::new(self.open_table(TABLE)?.range(..=key)?.rev().map(k)) } else { Box::new(self.open_table(TABLE)?.range(key..)?.map(k)) }) } }