mirror of
https://github.com/hinto-janai/cuprate.git
synced 2024-12-22 11:39:30 +00:00
Compare commits
4 commits
87de6de499
...
742cc0e69e
Author | SHA1 | Date | |
---|---|---|---|
|
742cc0e69e | ||
|
4f12612abc | ||
|
dd2f7e083d | ||
|
80272e14e9 |
10 changed files with 337 additions and 261 deletions
|
@ -28,10 +28,10 @@ pub fn update_alt_chain_info(
|
||||||
Err(e) => return Err(e),
|
Err(e) => return Err(e),
|
||||||
};
|
};
|
||||||
|
|
||||||
// try update the info if one exists for this chain.
|
tables
|
||||||
let update = tables
|
|
||||||
.alt_chain_infos_mut()
|
.alt_chain_infos_mut()
|
||||||
.update(&alt_block_height.chain_id, |mut info| {
|
.entry(&alt_block_height.chain_id)?
|
||||||
|
.and_update(|info| {
|
||||||
if info.chain_height < alt_block_height.height + 1 {
|
if info.chain_height < alt_block_height.height + 1 {
|
||||||
// If the chain height is increasing we only need to update the chain height.
|
// If the chain height is increasing we only need to update the chain height.
|
||||||
info.chain_height = alt_block_height.height + 1;
|
info.chain_height = alt_block_height.height + 1;
|
||||||
|
@ -43,25 +43,12 @@ pub fn update_alt_chain_info(
|
||||||
}
|
}
|
||||||
|
|
||||||
info.chain_height = alt_block_height.height + 1;
|
info.chain_height = alt_block_height.height + 1;
|
||||||
Some(info)
|
})?
|
||||||
});
|
.or_insert_with(|| AltChainInfo {
|
||||||
|
|
||||||
match update {
|
|
||||||
Ok(()) => return Ok(()),
|
|
||||||
Err(RuntimeError::KeyNotFound) => (),
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
}
|
|
||||||
|
|
||||||
// If one doesn't already exist add it.
|
|
||||||
|
|
||||||
tables.alt_chain_infos_mut().put(
|
|
||||||
&alt_block_height.chain_id,
|
|
||||||
&AltChainInfo {
|
|
||||||
parent_chain: parent_chain.into(),
|
parent_chain: parent_chain.into(),
|
||||||
common_ancestor_height: alt_block_height.height.checked_sub(1).unwrap(),
|
common_ancestor_height: alt_block_height.height.checked_sub(1).unwrap(),
|
||||||
chain_height: alt_block_height.height + 1,
|
chain_height: alt_block_height.height + 1,
|
||||||
},
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the height history of an alt-chain in reverse chronological order.
|
/// Get the height history of an alt-chain in reverse chronological order.
|
||||||
|
|
|
@ -62,19 +62,12 @@ pub fn remove_output(
|
||||||
pre_rct_output_id: &PreRctOutputId,
|
pre_rct_output_id: &PreRctOutputId,
|
||||||
tables: &mut impl TablesMut,
|
tables: &mut impl TablesMut,
|
||||||
) -> DbResult<()> {
|
) -> DbResult<()> {
|
||||||
// Decrement the amount index by 1, or delete the entry out-right.
|
// INVARIANT: `num_outputs` should never be 0.
|
||||||
// FIXME: this would be much better expressed with a
|
|
||||||
// `btree_map::Entry`-like API, fix `trait DatabaseRw`.
|
|
||||||
tables
|
tables
|
||||||
.num_outputs_mut()
|
.num_outputs_mut()
|
||||||
.update(&pre_rct_output_id.amount, |num_outputs| {
|
.entry(&pre_rct_output_id.amount)?
|
||||||
// INVARIANT: Should never be 0.
|
.remove_if(|num_outputs| *num_outputs == 1)?
|
||||||
if num_outputs == 1 {
|
.and_update(|num_outputs| *num_outputs -= 1)?;
|
||||||
None
|
|
||||||
} else {
|
|
||||||
Some(num_outputs - 1)
|
|
||||||
}
|
|
||||||
})?;
|
|
||||||
|
|
||||||
// Delete the output data itself.
|
// Delete the output data itself.
|
||||||
tables.outputs_mut().delete(pre_rct_output_id)
|
tables.outputs_mut().delete(pre_rct_output_id)
|
||||||
|
|
|
@ -263,17 +263,17 @@ fn db_read_write() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assert `update()` works.
|
// Assert `Entry` works.
|
||||||
{
|
{
|
||||||
const NEW_VALUE: u64 = 999;
|
const NEW_VALUE: u64 = 999;
|
||||||
|
|
||||||
assert_ne!(table.get(&KEY).unwrap(), NEW_VALUE);
|
assert_ne!(table.get(&KEY).unwrap(), NEW_VALUE);
|
||||||
|
|
||||||
#[expect(unused_assignments)]
|
|
||||||
table
|
table
|
||||||
.update(&KEY, |mut value| {
|
.entry(&KEY)
|
||||||
value = NEW_VALUE;
|
.unwrap()
|
||||||
Some(value)
|
.and_update(|value| {
|
||||||
|
*value = NEW_VALUE;
|
||||||
})
|
})
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
|
|
@ -179,30 +179,6 @@ pub trait DatabaseRw<T: Table>: DatabaseRo<T> + Sized {
|
||||||
#[doc = doc_database!()]
|
#[doc = doc_database!()]
|
||||||
fn take(&mut self, key: &T::Key) -> DbResult<T::Value>;
|
fn take(&mut self, key: &T::Key) -> DbResult<T::Value>;
|
||||||
|
|
||||||
/// Fetch the value, and apply a function to it - or delete the entry.
|
|
||||||
///
|
|
||||||
/// This will call [`DatabaseRo::get`] and call your provided function `f` on it.
|
|
||||||
///
|
|
||||||
/// The [`Option`] `f` returns will dictate whether `update()`:
|
|
||||||
/// - Updates the current value OR
|
|
||||||
/// - Deletes the `(key, value)` pair
|
|
||||||
///
|
|
||||||
/// - If `f` returns `Some(value)`, that will be [`DatabaseRw::put`] as the new value
|
|
||||||
/// - If `f` returns `None`, the entry will be [`DatabaseRw::delete`]d
|
|
||||||
///
|
|
||||||
#[doc = doc_database!()]
|
|
||||||
fn update<F>(&mut self, key: &T::Key, mut f: F) -> DbResult<()>
|
|
||||||
where
|
|
||||||
F: FnMut(T::Value) -> Option<T::Value>,
|
|
||||||
{
|
|
||||||
let value = DatabaseRo::get(self, key)?;
|
|
||||||
|
|
||||||
match f(value) {
|
|
||||||
Some(value) => DatabaseRw::put(self, key, &value),
|
|
||||||
None => DatabaseRw::delete(self, key),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Removes and returns the first `(key, value)` pair in the database.
|
/// Removes and returns the first `(key, value)` pair in the database.
|
||||||
///
|
///
|
||||||
#[doc = doc_database!()]
|
#[doc = doc_database!()]
|
||||||
|
@ -213,6 +189,8 @@ pub trait DatabaseRw<T: Table>: DatabaseRo<T> + Sized {
|
||||||
#[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
|
/// Gets the given key's corresponding entry for in-place manipulation.
|
||||||
|
///
|
||||||
|
#[doc = doc_database!()]
|
||||||
fn entry<'a>(&'a mut self, key: &'a T::Key) -> DbResult<Entry<'a, T, Self>>;
|
fn entry<'a>(&'a mut self, key: &'a T::Key) -> DbResult<Entry<'a, T, Self>>;
|
||||||
}
|
}
|
||||||
|
|
315
storage/database/src/entry.rs
Normal file
315
storage/database/src/entry.rs
Normal file
|
@ -0,0 +1,315 @@
|
||||||
|
//! Entry API for [`DatabaseRw`].
|
||||||
|
//!
|
||||||
|
//! This module provides a [`std::collections::btree_map::Entry`]-like API for [`DatabaseRw`].
|
||||||
|
//!
|
||||||
|
//! ## Example
|
||||||
|
//! ```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));
|
||||||
|
//! table.entry(&KEY)?.and_update(f)?.or_insert(&0)?;
|
||||||
|
//! assert_eq!(table.first()?, (KEY, 1));
|
||||||
|
//!
|
||||||
|
//! // Conditionally remove the entry.
|
||||||
|
//! table.entry(&KEY)?.remove_if(|v| *v == 0);
|
||||||
|
//! assert_eq!(table.first()?, (KEY, 1));
|
||||||
|
//! table.entry(&KEY)?.remove_if(|v| *v == 1);
|
||||||
|
//! assert!(matches!(table.first(), Err(RuntimeError::KeyNotFound)));
|
||||||
|
//! # Ok(()) }
|
||||||
|
//! ```
|
||||||
|
|
||||||
|
use crate::{DatabaseRw, DbResult, RuntimeError, Table};
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- Entry
|
||||||
|
/// A view into a single entry in a [`DatabaseRw`], which may either be a [`VacantEntry`] or [`OccupiedEntry`].
|
||||||
|
///
|
||||||
|
/// This enum is constructed from the [`DatabaseRw::entry`] method.
|
||||||
|
pub enum Entry<'a, T, D>
|
||||||
|
where
|
||||||
|
T: Table,
|
||||||
|
D: DatabaseRw<T>,
|
||||||
|
{
|
||||||
|
/// A vacant entry; this key did not exist.
|
||||||
|
///
|
||||||
|
/// [`RuntimeError::KeyExists`] will never be returned from this type's operations.
|
||||||
|
Vacant(VacantEntry<'a, T, D>),
|
||||||
|
|
||||||
|
/// An occupied entry; this key already exists.
|
||||||
|
///
|
||||||
|
/// [`RuntimeError::KeyNotFound`] will never be returned from this type's operations.
|
||||||
|
Occupied(OccupiedEntry<'a, T, D>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a, T, D> Entry<'a, T, D>
|
||||||
|
where
|
||||||
|
T: Table,
|
||||||
|
D: DatabaseRw<T>,
|
||||||
|
{
|
||||||
|
/// Returns [`true`] if [`Self::Occupied`].
|
||||||
|
pub const fn is_occupied(&self) -> bool {
|
||||||
|
matches!(self, Self::Occupied(_))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns [`true`] if [`Self::Vacant`].
|
||||||
|
pub const fn is_vacant(&self) -> bool {
|
||||||
|
matches!(self, Self::Vacant(_))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<()> {
|
||||||
|
match self {
|
||||||
|
Self::Occupied(_) => Ok(()),
|
||||||
|
Self::Vacant(entry) => entry.insert(default),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<()>
|
||||||
|
where
|
||||||
|
F: FnOnce() -> T::Value,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Occupied(_) => Ok(()),
|
||||||
|
Self::Vacant(entry) => entry.insert(&default()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Same as [`Self::or_insert_with`] but gives access to the key.
|
||||||
|
pub fn or_insert_with_key<F>(self, default: F) -> DbResult<()>
|
||||||
|
where
|
||||||
|
F: FnOnce(&'a T::Key) -> T::Value,
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Occupied(_) => Ok(()),
|
||||||
|
Self::Vacant(entry) => {
|
||||||
|
let key = entry.key;
|
||||||
|
entry.insert(&default(key))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to this entry's key.
|
||||||
|
pub const fn key(&self) -> &T::Key {
|
||||||
|
match self {
|
||||||
|
Self::Occupied(entry) => entry.key(),
|
||||||
|
Self::Vacant(entry) => entry.key(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns a reference to this entry's value (if the entry is [`OccupiedEntry`]).
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This returns [`RuntimeError::KeyNotFound`] if the entry is [`VacantEntry`].
|
||||||
|
pub const fn value(&self) -> DbResult<&T::Value> {
|
||||||
|
match self {
|
||||||
|
Self::Occupied(entry) => Ok(entry.value()),
|
||||||
|
Self::Vacant(_) => Err(RuntimeError::KeyNotFound),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Take ownership of entry's value (if the entry is [`OccupiedEntry`]).
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
/// This returns [`RuntimeError::KeyNotFound`] if the entry is [`VacantEntry`].
|
||||||
|
pub fn into_value(self) -> DbResult<T::Value> {
|
||||||
|
match self {
|
||||||
|
Self::Occupied(entry) => Ok(entry.into_value()),
|
||||||
|
Self::Vacant(_) => Err(RuntimeError::KeyNotFound),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Conditionally remove the value if it already exists.
|
||||||
|
///
|
||||||
|
/// If `f` returns `true`, the entry will be removed if it exists.
|
||||||
|
///
|
||||||
|
/// This functions does nothing if the entry is [`VacantEntry`].
|
||||||
|
pub fn remove_if<F>(self, f: F) -> DbResult<Self>
|
||||||
|
where
|
||||||
|
F: FnOnce(&T::Value) -> bool,
|
||||||
|
{
|
||||||
|
Ok(match self {
|
||||||
|
Self::Occupied(entry) => {
|
||||||
|
if f(&entry.value) {
|
||||||
|
Self::Vacant(entry.remove()?.0)
|
||||||
|
} else {
|
||||||
|
Self::Occupied(entry)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Self::Vacant(entry) => Self::Vacant(entry),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Update the value if it already exists.
|
||||||
|
///
|
||||||
|
/// This functions does nothing if the entry is [`VacantEntry`].
|
||||||
|
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<T, D> Entry<'_, T, D>
|
||||||
|
where
|
||||||
|
T: Table,
|
||||||
|
<T as Table>::Value: Default,
|
||||||
|
D: DatabaseRw<T>,
|
||||||
|
{
|
||||||
|
/// Ensures a value is in the entry by inserting a [`Default`] value if empty.
|
||||||
|
///
|
||||||
|
/// 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()),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- VacantEntry
|
||||||
|
/// A view into a vacant [`Entry`] in a [`DatabaseRw`].
|
||||||
|
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>,
|
||||||
|
{
|
||||||
|
/// Gets a reference to the key that is used when [`Self::insert`]ing a value.
|
||||||
|
pub const fn key(&self) -> &T::Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
/// [`DatabaseRw::put`] a new value with [`Self::key`] as the key.
|
||||||
|
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),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//---------------------------------------------------------------------------------------------------- OccupiedEntry
|
||||||
|
/// A view into an occupied [`Entry`] in a [`DatabaseRw`].
|
||||||
|
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<'a, T, D> OccupiedEntry<'a, T, D>
|
||||||
|
where
|
||||||
|
T: Table,
|
||||||
|
D: DatabaseRw<T>,
|
||||||
|
{
|
||||||
|
/// Gets a reference to the key that is used when [`Self::insert`]ing a value.
|
||||||
|
pub const fn key(&self) -> &T::Key {
|
||||||
|
self.key
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Gets a reference to the current value.
|
||||||
|
///
|
||||||
|
/// [`Self::update`] will modify this value.
|
||||||
|
pub const fn value(&self) -> &T::Value {
|
||||||
|
&self.value
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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<()>
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut T::Value),
|
||||||
|
{
|
||||||
|
f(&mut self.value);
|
||||||
|
DatabaseRw::put(self.db, self.key, &self.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Replace the current value with a new value.
|
||||||
|
pub fn insert(self, value: &T::Value) -> DbResult<()> {
|
||||||
|
DatabaseRw::put(self.db, self.key, value)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Remove this entry.
|
||||||
|
///
|
||||||
|
/// The returned values are:
|
||||||
|
/// - A [`VacantEntry`]
|
||||||
|
/// - The value that was removed
|
||||||
|
pub fn remove(self) -> DbResult<(VacantEntry<'a, T, D>, T::Value)> {
|
||||||
|
DatabaseRw::delete(self.db, self.key)?;
|
||||||
|
Ok((
|
||||||
|
VacantEntry {
|
||||||
|
db: self.db,
|
||||||
|
key: self.key,
|
||||||
|
},
|
||||||
|
self.value,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,96 +0,0 @@
|
||||||
//! 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!()
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,10 +0,0 @@
|
||||||
//! 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;
|
|
|
@ -1,58 +0,0 @@
|
||||||
//! 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
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,34 +0,0 @@
|
||||||
//! 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),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -114,10 +114,11 @@ fn promote(env: &ConcreteEnv, tx_hash: &TransactionHash) -> DbResult<TxpoolWrite
|
||||||
let res = || {
|
let res = || {
|
||||||
let mut tx_infos = env_inner.open_db_rw::<TransactionInfos>(&tx_rw)?;
|
let mut tx_infos = env_inner.open_db_rw::<TransactionInfos>(&tx_rw)?;
|
||||||
|
|
||||||
tx_infos.update(tx_hash, |mut info| {
|
tx_infos.entry(tx_hash)?.and_update(|info| {
|
||||||
info.flags.remove(TxStateFlags::STATE_STEM);
|
info.flags.remove(TxStateFlags::STATE_STEM);
|
||||||
Some(info)
|
})?;
|
||||||
})
|
|
||||||
|
Ok(())
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = res() {
|
if let Err(e) = res() {
|
||||||
|
|
Loading…
Reference in a new issue