docs, example

This commit is contained in:
hinto.janai 2024-12-15 11:27:38 -05:00
parent 87de6de499
commit 80272e14e9
No known key found for this signature in database
GPG key ID: D47CE05FA175A499
4 changed files with 103 additions and 32 deletions

View file

@ -1,16 +1,26 @@
//! TODO //! [`Entry`]
use crate::{ use crate::{
entry::{OccupiedEntry, VacantEntry}, entry::{OccupiedEntry, VacantEntry},
DatabaseRw, DbResult, Table, DatabaseRw, DbResult, Table,
}; };
/// A view into a single entry in a [`DatabaseRw`], which may either be vacant or occupied.
///
/// This enum is constructed from the [`DatabaseRw::entry`] method.
pub enum Entry<'a, T, D> pub enum Entry<'a, T, D>
where where
T: Table, T: Table,
D: DatabaseRw<T>, D: DatabaseRw<T>,
{ {
/// A vacant entry; this key did not exist.
///
/// [`crate::Runtime::KeyExists`] will never be returned from this type's operations.
Vacant(VacantEntry<'a, T, D>), Vacant(VacantEntry<'a, T, D>),
/// An occupied entry; this key already exists.
///
/// [`crate::Runtime::KeyNotFound`] will never be returned from this type's operations.
Occupied(OccupiedEntry<'a, T, D>), Occupied(OccupiedEntry<'a, T, D>),
} }
@ -19,7 +29,9 @@ where
T: Table, T: Table,
D: DatabaseRw<T>, D: DatabaseRw<T>,
{ {
/// TODO /// Ensures a value is in the entry by inserting the `default` if empty.
///
/// This only inserts if the entry is [`VacantEntry`].
pub fn or_insert(self, default: &T::Value) -> DbResult<()> { pub fn or_insert(self, default: &T::Value) -> DbResult<()> {
match self { match self {
Self::Occupied(_) => Ok(()), Self::Occupied(_) => Ok(()),
@ -27,7 +39,9 @@ where
} }
} }
/// TODO /// Ensures a value is in the entry by inserting the result of the `default` function.
///
/// This only inserts if the entry is [`VacantEntry`].
pub fn or_insert_with<F>(self, default: F) -> DbResult<()> pub fn or_insert_with<F>(self, default: F) -> DbResult<()>
where where
F: FnOnce() -> &'a T::Value, F: FnOnce() -> &'a T::Value,
@ -38,7 +52,7 @@ where
} }
} }
/// TODO /// Same as [`Self::or_insert_with`] but gives access to the key.
pub fn or_insert_with_key<F>(self, default: F) -> DbResult<()> pub fn or_insert_with_key<F>(self, default: F) -> DbResult<()>
where where
F: FnOnce(&'a T::Key) -> &'a T::Value, F: FnOnce(&'a T::Key) -> &'a T::Value,
@ -52,7 +66,7 @@ where
} }
} }
/// TODO /// Returns a reference to this entry's key.
pub const fn key(&self) -> &T::Key { pub const fn key(&self) -> &T::Key {
match self { match self {
Self::Occupied(entry) => entry.key(), Self::Occupied(entry) => entry.key(),
@ -60,7 +74,7 @@ where
} }
} }
/// TODO /// Returns a reference to this entry's key (if the entry is [`OccupiedEntry`]).
pub const fn value(&self) -> Option<&T::Value> { pub const fn value(&self) -> Option<&T::Value> {
match self { match self {
Self::Occupied(entry) => Some(entry.value()), Self::Occupied(entry) => Some(entry.value()),
@ -68,7 +82,7 @@ where
} }
} }
/// TODO /// Provides in-place mutable access to an occupied entry before any potential inserts.
pub fn and_update<F>(self, f: F) -> DbResult<Self> pub fn and_update<F>(self, f: F) -> DbResult<Self>
where where
F: FnOnce(&mut T::Value), F: FnOnce(&mut T::Value),
@ -83,14 +97,19 @@ where
} }
} }
impl<'a, T, D> Entry<'a, T, D> impl<T, D> Entry<'_, T, D>
where where
T: Table, T: Table,
<T as Table>::Value: Default, <T as Table>::Value: Default,
D: DatabaseRw<T>, D: DatabaseRw<T>,
{ {
/// TODO /// Ensures a value is in the entry by inserting a [`Default`] value if empty.
pub fn or_default(self) -> &'a mut T::Value { ///
todo!() /// This only inserts if the entry is [`VacantEntry`].
pub fn or_default(self) -> DbResult<()> {
match self {
Self::Occupied(_) => Ok(()),
Self::Vacant(entry) => entry.insert(&Default::default()),
}
} }
} }

View file

@ -1,4 +1,55 @@
//! TODO //! `(key, value)` entry API for [`crate::DatabaseRw`].
//!
//! This module provides a [`std::collections::btree_map::Entry`]-like API for [`crate::DatabaseRw`].
//!
//! ## Example - modifying a value in place, or inserting it if it doesn't exist
//! ```rust
//! use cuprate_database::{
//! ConcreteEnv,
//! config::ConfigBuilder,
//! Env, EnvInner,
//! DatabaseRo, DatabaseRw, TxRo, TxRw, RuntimeError,
//! };
//!
//! # fn main() -> Result<(), Box<dyn std::error::Error>> {
//! # let tmp_dir = tempfile::tempdir()?;
//! # let db_dir = tmp_dir.path().to_owned();
//! # let config = ConfigBuilder::new(db_dir.into()).build();
//! #
//! # let env = ConcreteEnv::open(config)?;
//! #
//! # struct Table;
//! # impl cuprate_database::Table for Table {
//! # const NAME: &'static str = "table";
//! # type Key = u8;
//! # type Value = u64;
//! # }
//! #
//! # let env_inner = env.env_inner();
//! # let tx_rw = env_inner.tx_rw()?;
//! #
//! # env_inner.create_db::<Table>(&tx_rw)?;
//! # let mut table = env_inner.open_db_rw::<Table>(&tx_rw)?;
//! /// The key to use.
//! const KEY: u8 = u8::MAX;
//!
//! /// The update function applied if the value already exists.
//! fn f(value: &mut u64) {
//! *value += 1;
//! }
//!
//! // No entry exists.
//! assert!(matches!(table.first(), Err(RuntimeError::KeyNotFound)));
//!
//! // Increment the value by `1` or insert a `0` if it doesn't exist.
//! table.entry(&KEY)?.and_update(f)?.or_insert(&0)?;
//! assert_eq!(table.first()?, (KEY, 0));
//!
//! // Again.
//! table.entry(&KEY)?.and_update(f)?.or_insert(&0)?;
//! assert_eq!(table.first()?, (KEY, 1));
//! # Ok(()) }
//! ```
#[expect(clippy::module_inception)] #[expect(clippy::module_inception)]
mod entry; mod entry;

View file

@ -1,7 +1,8 @@
//! TODO //! [`OccupiedEntry`]
use crate::{DatabaseRw, DbResult, Table}; use crate::{DatabaseRw, DbResult, Table};
/// A view into an occupied entry in a [`DatabaseRw`]. It is part of [`crate::entry::Entry`].
pub struct OccupiedEntry<'a, T, D> pub struct OccupiedEntry<'a, T, D>
where where
T: Table, T: Table,
@ -17,17 +18,26 @@ where
T: Table, T: Table,
D: DatabaseRw<T>, D: DatabaseRw<T>,
{ {
/// TODO /// Gets a reference to the key that is used when [`Self::insert`]ing a value.
pub const fn key(&self) -> &T::Key { pub const fn key(&self) -> &T::Key {
self.key self.key
} }
/// TODO /// Gets a reference to the current value.
///
/// [`Self::update`] will modify this value.
pub const fn value(&self) -> &T::Value { pub const fn value(&self) -> &T::Value {
&self.value &self.value
} }
/// TODO /// Take ownership of the current value.
pub fn into_value(self) -> T::Value {
self.value
}
/// Modify the current value and insert it.
///
/// Calling [`Self::value`] after this will return the modified value.
pub fn update<F>(&mut self, f: F) -> DbResult<()> pub fn update<F>(&mut self, f: F) -> DbResult<()>
where where
F: FnOnce(&mut T::Value), F: FnOnce(&mut T::Value),
@ -36,23 +46,13 @@ where
DatabaseRw::put(self.db, self.key, &self.value) DatabaseRw::put(self.db, self.key, &self.value)
} }
/// TODO /// Replace the current value with a new value.
pub fn insert(&mut self, value: &T::Value) -> DbResult<()> { pub fn insert(self, value: &T::Value) -> DbResult<()> {
DatabaseRw::put(self.db, self.key, value) DatabaseRw::put(self.db, self.key, value)
} }
/// TODO /// Remove this entry.
pub fn remove(self) -> DbResult<T::Value> { pub fn remove(self) -> DbResult<T::Value> {
DatabaseRw::delete(self.db, self.key).map(|()| Ok(self.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
}
} }

View file

@ -1,7 +1,8 @@
//! TODO //! [`VacantEntry`]
use crate::{DatabaseRw, DbResult, RuntimeError, Table}; use crate::{DatabaseRw, DbResult, RuntimeError, Table};
/// A view into a vacant entry in a [`DatabaseRw`]. It is part of [`crate::entry::Entry`].
pub struct VacantEntry<'a, T, D> pub struct VacantEntry<'a, T, D>
where where
T: Table, T: Table,
@ -16,12 +17,12 @@ where
T: Table, T: Table,
D: DatabaseRw<T>, D: DatabaseRw<T>,
{ {
/// TODO /// Gets a reference to the key that is used when [`Self::insert`]ing a value.
pub const fn key(&self) -> &T::Key { pub const fn key(&self) -> &T::Key {
self.key self.key
} }
/// TODO /// [`DatabaseRw::put`] a new value with [`Self::key`] as the key.
pub fn insert(self, value: &T::Value) -> DbResult<()> { pub fn insert(self, value: &T::Value) -> DbResult<()> {
match DatabaseRw::put(self.db, self.key, value) { match DatabaseRw::put(self.db, self.key, value) {
Ok(()) => Ok(()), Ok(()) => Ok(()),