/* 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) 2026 metamuffin */ use anyhow::Result; use redb::{AccessGuard, ReadableTable, StorageError, Table, TableDefinition}; use std::path::Path; use crate::{Store, Transaction}; const TABLE: TableDefinition<&[u8], &[u8]> = TableDefinition::new("kv"); pub fn new(path: &Path) -> Result { Ok(redb::Database::create(path)?) } impl Store for redb::Database { fn transaction(&self, f: &mut dyn FnMut(&mut dyn Transaction) -> Result<()>) -> Result<()> { let txn = self.begin_write()?; let mut table = txn.open_table(TABLE)?; f(&mut table)?; drop(table); txn.commit()?; Ok(()) } } impl Transaction for Table<'_, &[u8], &[u8]> { fn set(&mut self, key: &[u8], value: &[u8]) -> Result<()> { self.insert(key, value)?; Ok(()) } fn del(&mut self, key: &[u8]) -> Result<()> { self.remove(key)?; Ok(()) } fn get<'a>(&'a self, key: &[u8]) -> Result>> { match ReadableTable::get(self, 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.range(..=key)?.rev().map(k)) } else { Box::new(self.range(key..)?.map(k)) }) } }