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::{
|
use crate::{
|
||||||
backend::heed::types::HeedDb,
|
backend::heed::types::HeedDb,
|
||||||
database::{DatabaseIter, DatabaseRo, DatabaseRw},
|
database::{DatabaseIter, DatabaseRo, DatabaseRw},
|
||||||
|
entry::{Entry, OccupiedEntry, VacantEntry},
|
||||||
error::{DbResult, RuntimeError},
|
error::{DbResult, RuntimeError},
|
||||||
table::Table,
|
table::Table,
|
||||||
};
|
};
|
||||||
|
@ -239,6 +240,19 @@ impl<T: Table> DatabaseRw<T> for HeedTableRw<'_, '_, T> {
|
||||||
Ok(false) => unreachable!(),
|
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
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
|
|
|
@ -11,6 +11,7 @@ use crate::{
|
||||||
types::{RedbTableRo, RedbTableRw},
|
types::{RedbTableRo, RedbTableRw},
|
||||||
},
|
},
|
||||||
database::{DatabaseIter, DatabaseRo, DatabaseRw},
|
database::{DatabaseIter, DatabaseRo, DatabaseRw},
|
||||||
|
entry::{Entry, OccupiedEntry, VacantEntry},
|
||||||
error::{DbResult, RuntimeError},
|
error::{DbResult, RuntimeError},
|
||||||
table::Table,
|
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.
|
// `redb` returns the value after function calls so we end with Ok(()) instead.
|
||||||
|
|
||||||
#[inline]
|
#[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)?;
|
let (key, value) = redb::Table::pop_last(self)?.ok_or(RuntimeError::KeyNotFound)?;
|
||||||
Ok((key.value(), value.value()))
|
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
|
//---------------------------------------------------------------------------------------------------- Tests
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
use std::ops::RangeBounds;
|
use std::ops::RangeBounds;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
entry::Entry,
|
||||||
error::{DbResult, RuntimeError},
|
error::{DbResult, RuntimeError},
|
||||||
table::Table,
|
table::Table,
|
||||||
};
|
};
|
||||||
|
@ -151,7 +152,7 @@ pub unsafe trait DatabaseRo<T: Table> {
|
||||||
/// Database (key-value store) read/write abstraction.
|
/// Database (key-value store) read/write abstraction.
|
||||||
///
|
///
|
||||||
/// All [`DatabaseRo`] functions are also callable by [`DatabaseRw`].
|
/// 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.
|
/// Insert a key-value pair into the database.
|
||||||
///
|
///
|
||||||
/// This will overwrite any existing key-value pairs.
|
/// This will overwrite any existing key-value pairs.
|
||||||
|
@ -211,4 +212,7 @@ pub trait DatabaseRw<T: Table>: DatabaseRo<T> {
|
||||||
///
|
///
|
||||||
#[doc = doc_database!()]
|
#[doc = doc_database!()]
|
||||||
fn pop_last(&mut self) -> DbResult<(T::Key, T::Value)>;
|
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;
|
mod transaction;
|
||||||
|
|
||||||
pub mod config;
|
pub mod config;
|
||||||
|
pub mod entry;
|
||||||
pub mod resize;
|
pub mod resize;
|
||||||
|
|
||||||
pub use backend::ConcreteEnv;
|
pub use backend::ConcreteEnv;
|
||||||
|
|
Loading…
Reference in a new issue