mirror of
https://github.com/hinto-janai/cuprate.git
synced 2025-01-03 09:29:39 +00:00
impl src/entry
, traits, backends
This commit is contained in:
parent
7b8756fa80
commit
87de6de499
8 changed files with 233 additions and 2 deletions
|
@ -6,6 +6,7 @@ use std::{cell::RefCell, ops::RangeBounds};
|
|||
use crate::{
|
||||
backend::heed::types::HeedDb,
|
||||
database::{DatabaseIter, DatabaseRo, DatabaseRw},
|
||||
entry::{Entry, OccupiedEntry, VacantEntry},
|
||||
error::{DbResult, RuntimeError},
|
||||
table::Table,
|
||||
};
|
||||
|
@ -239,6 +240,19 @@ impl<T: Table> DatabaseRw<T> for HeedTableRw<'_, '_, T> {
|
|||
Ok(false) => unreachable!(),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn entry<'a>(&'a mut self, key: &'a T::Key) -> DbResult<Entry<'a, T, Self>> {
|
||||
match DatabaseRo::get(self, key) {
|
||||
Ok(value) => Ok(Entry::Occupied(OccupiedEntry {
|
||||
db: self,
|
||||
key,
|
||||
value,
|
||||
})),
|
||||
Err(RuntimeError::KeyNotFound) => Ok(Entry::Vacant(VacantEntry { db: self, key })),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Tests
|
||||
|
|
|
@ -11,6 +11,7 @@ use crate::{
|
|||
types::{RedbTableRo, RedbTableRw},
|
||||
},
|
||||
database::{DatabaseIter, DatabaseRo, DatabaseRw},
|
||||
entry::{Entry, OccupiedEntry, VacantEntry},
|
||||
error::{DbResult, RuntimeError},
|
||||
table::Table,
|
||||
};
|
||||
|
@ -162,7 +163,7 @@ unsafe impl<T: Table + 'static> DatabaseRo<T> for RedbTableRw<'_, T::Key, T::Val
|
|||
}
|
||||
}
|
||||
|
||||
impl<T: Table + 'static> DatabaseRw<T> for RedbTableRw<'_, T::Key, T::Value> {
|
||||
impl<T: Table> DatabaseRw<T> for RedbTableRw<'_, T::Key, T::Value> {
|
||||
// `redb` returns the value after function calls so we end with Ok(()) instead.
|
||||
|
||||
#[inline]
|
||||
|
@ -197,6 +198,19 @@ impl<T: Table + 'static> DatabaseRw<T> for RedbTableRw<'_, T::Key, T::Value> {
|
|||
let (key, value) = redb::Table::pop_last(self)?.ok_or(RuntimeError::KeyNotFound)?;
|
||||
Ok((key.value(), value.value()))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn entry<'a>(&'a mut self, key: &'a T::Key) -> DbResult<Entry<'a, T, Self>> {
|
||||
match get::<T>(self, key) {
|
||||
Ok(value) => Ok(Entry::Occupied(OccupiedEntry {
|
||||
db: self,
|
||||
key,
|
||||
value,
|
||||
})),
|
||||
Err(RuntimeError::KeyNotFound) => Ok(Entry::Vacant(VacantEntry { db: self, key })),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------------------------------------- Tests
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
use std::ops::RangeBounds;
|
||||
|
||||
use crate::{
|
||||
entry::Entry,
|
||||
error::{DbResult, RuntimeError},
|
||||
table::Table,
|
||||
};
|
||||
|
@ -151,7 +152,7 @@ pub unsafe trait DatabaseRo<T: Table> {
|
|||
/// Database (key-value store) read/write abstraction.
|
||||
///
|
||||
/// All [`DatabaseRo`] functions are also callable by [`DatabaseRw`].
|
||||
pub trait DatabaseRw<T: Table>: DatabaseRo<T> {
|
||||
pub trait DatabaseRw<T: Table>: DatabaseRo<T> + Sized {
|
||||
/// Insert a key-value pair into the database.
|
||||
///
|
||||
/// This will overwrite any existing key-value pairs.
|
||||
|
@ -211,4 +212,7 @@ pub trait DatabaseRw<T: Table>: DatabaseRo<T> {
|
|||
///
|
||||
#[doc = doc_database!()]
|
||||
fn pop_last(&mut self) -> DbResult<(T::Key, T::Value)>;
|
||||
|
||||
/// TODO
|
||||
fn entry<'a>(&'a mut self, key: &'a T::Key) -> DbResult<Entry<'a, T, Self>>;
|
||||
}
|
||||
|
|
96
storage/database/src/entry/entry.rs
Normal file
96
storage/database/src/entry/entry.rs
Normal file
|
@ -0,0 +1,96 @@
|
|||
//! TODO
|
||||
|
||||
use crate::{
|
||||
entry::{OccupiedEntry, VacantEntry},
|
||||
DatabaseRw, DbResult, Table,
|
||||
};
|
||||
|
||||
pub enum Entry<'a, T, D>
|
||||
where
|
||||
T: Table,
|
||||
D: DatabaseRw<T>,
|
||||
{
|
||||
Vacant(VacantEntry<'a, T, D>),
|
||||
Occupied(OccupiedEntry<'a, T, D>),
|
||||
}
|
||||
|
||||
impl<'a, T, D> Entry<'a, T, D>
|
||||
where
|
||||
T: Table,
|
||||
D: DatabaseRw<T>,
|
||||
{
|
||||
/// TODO
|
||||
pub fn or_insert(self, default: &T::Value) -> DbResult<()> {
|
||||
match self {
|
||||
Self::Occupied(_) => Ok(()),
|
||||
Self::Vacant(entry) => entry.insert(default),
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn or_insert_with<F>(self, default: F) -> DbResult<()>
|
||||
where
|
||||
F: FnOnce() -> &'a T::Value,
|
||||
{
|
||||
match self {
|
||||
Self::Occupied(_) => Ok(()),
|
||||
Self::Vacant(entry) => entry.insert(default()),
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn or_insert_with_key<F>(self, default: F) -> DbResult<()>
|
||||
where
|
||||
F: FnOnce(&'a T::Key) -> &'a T::Value,
|
||||
{
|
||||
match self {
|
||||
Self::Occupied(_) => Ok(()),
|
||||
Self::Vacant(entry) => {
|
||||
let key = entry.key;
|
||||
entry.insert(default(key))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub const fn key(&self) -> &T::Key {
|
||||
match self {
|
||||
Self::Occupied(entry) => entry.key(),
|
||||
Self::Vacant(entry) => entry.key(),
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub const fn value(&self) -> Option<&T::Value> {
|
||||
match self {
|
||||
Self::Occupied(entry) => Some(entry.value()),
|
||||
Self::Vacant(_) => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn and_update<F>(self, f: F) -> DbResult<Self>
|
||||
where
|
||||
F: FnOnce(&mut T::Value),
|
||||
{
|
||||
Ok(match self {
|
||||
Self::Occupied(mut entry) => {
|
||||
entry.update(f)?;
|
||||
Self::Occupied(entry)
|
||||
}
|
||||
Self::Vacant(entry) => Self::Vacant(entry),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T, D> Entry<'a, T, D>
|
||||
where
|
||||
T: Table,
|
||||
<T as Table>::Value: Default,
|
||||
D: DatabaseRw<T>,
|
||||
{
|
||||
/// TODO
|
||||
pub fn or_default(self) -> &'a mut T::Value {
|
||||
todo!()
|
||||
}
|
||||
}
|
10
storage/database/src/entry/mod.rs
Normal file
10
storage/database/src/entry/mod.rs
Normal file
|
@ -0,0 +1,10 @@
|
|||
//! TODO
|
||||
|
||||
#[expect(clippy::module_inception)]
|
||||
mod entry;
|
||||
mod occupied_entry;
|
||||
mod vacant_entry;
|
||||
|
||||
pub use entry::Entry;
|
||||
pub use occupied_entry::OccupiedEntry;
|
||||
pub use vacant_entry::VacantEntry;
|
58
storage/database/src/entry/occupied_entry.rs
Normal file
58
storage/database/src/entry/occupied_entry.rs
Normal file
|
@ -0,0 +1,58 @@
|
|||
//! TODO
|
||||
|
||||
use crate::{DatabaseRw, DbResult, Table};
|
||||
|
||||
pub struct OccupiedEntry<'a, T, D>
|
||||
where
|
||||
T: Table,
|
||||
D: DatabaseRw<T>,
|
||||
{
|
||||
pub(crate) db: &'a mut D,
|
||||
pub(crate) key: &'a T::Key,
|
||||
pub(crate) value: T::Value,
|
||||
}
|
||||
|
||||
impl<T, D> OccupiedEntry<'_, T, D>
|
||||
where
|
||||
T: Table,
|
||||
D: DatabaseRw<T>,
|
||||
{
|
||||
/// TODO
|
||||
pub const fn key(&self) -> &T::Key {
|
||||
self.key
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub const fn value(&self) -> &T::Value {
|
||||
&self.value
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn update<F>(&mut self, f: F) -> DbResult<()>
|
||||
where
|
||||
F: FnOnce(&mut T::Value),
|
||||
{
|
||||
f(&mut self.value);
|
||||
DatabaseRw::put(self.db, self.key, &self.value)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn insert(&mut self, value: &T::Value) -> DbResult<()> {
|
||||
DatabaseRw::put(self.db, self.key, value)
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn remove(self) -> DbResult<T::Value> {
|
||||
DatabaseRw::delete(self.db, self.key).map(|()| Ok(self.value))?
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub const fn get(&self) -> &T::Value {
|
||||
&self.value
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn into_value(self) -> T::Value {
|
||||
self.value
|
||||
}
|
||||
}
|
34
storage/database/src/entry/vacant_entry.rs
Normal file
34
storage/database/src/entry/vacant_entry.rs
Normal file
|
@ -0,0 +1,34 @@
|
|||
//! TODO
|
||||
|
||||
use crate::{DatabaseRw, DbResult, RuntimeError, Table};
|
||||
|
||||
pub struct VacantEntry<'a, T, D>
|
||||
where
|
||||
T: Table,
|
||||
D: DatabaseRw<T>,
|
||||
{
|
||||
pub(crate) db: &'a mut D,
|
||||
pub(crate) key: &'a T::Key,
|
||||
}
|
||||
|
||||
impl<T, D> VacantEntry<'_, T, D>
|
||||
where
|
||||
T: Table,
|
||||
D: DatabaseRw<T>,
|
||||
{
|
||||
/// TODO
|
||||
pub const fn key(&self) -> &T::Key {
|
||||
self.key
|
||||
}
|
||||
|
||||
/// TODO
|
||||
pub fn insert(self, value: &T::Value) -> DbResult<()> {
|
||||
match DatabaseRw::put(self.db, self.key, value) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(RuntimeError::KeyExists) => {
|
||||
unreachable!("this error popping up while VacantEntry exists is a logical error")
|
||||
}
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
}
|
|
@ -42,6 +42,7 @@ mod tables;
|
|||
mod transaction;
|
||||
|
||||
pub mod config;
|
||||
pub mod entry;
|
||||
pub mod resize;
|
||||
|
||||
pub use backend::ConcreteEnv;
|
||||
|
|
Loading…
Reference in a new issue