use std::fmt::{self as StdFmt, Debug, Formatter};
use seize::LocalGuard;
use crate::{MassTreeGeneric, TreeAllocator, policy::LeafPolicy, tree::RemoveError};
pub type RemoveEntryResult<O> = Result<Option<(Vec<u8>, O)>, RemoveError>;
pub enum Entry<'t, 'e, P, A>
where
P: LeafPolicy,
A: TreeAllocator<P>,
{
Occupied(OccupiedEntry<'t, 'e, P, A>),
Vacant(VacantEntry<'t, 'e, P, A>),
}
pub struct OccupiedEntry<'t, 'e, P, A>
where
P: LeafPolicy,
A: TreeAllocator<P>,
{
key: &'e [u8],
value: P::Output,
tree: &'t MassTreeGeneric<P, A>,
guard: &'e LocalGuard<'t>,
}
pub struct VacantEntry<'t, 'e, P, A>
where
P: LeafPolicy,
A: TreeAllocator<P>,
{
key: &'e [u8],
tree: &'t MassTreeGeneric<P, A>,
guard: &'e LocalGuard<'t>,
}
impl<'t, 'e, P, A> Entry<'t, 'e, P, A>
where
P: LeafPolicy,
A: TreeAllocator<P>,
{
#[must_use]
#[inline(always)]
pub const fn key(&self) -> &[u8] {
match self {
Entry::Occupied(o) => o.key(),
Entry::Vacant(v) => v.key(),
}
}
#[inline(always)]
pub fn or_insert(self, default: P::Value) -> P::Output {
match self {
Entry::Occupied(o) => o.into_value(),
Entry::Vacant(v) => v.insert(default),
}
}
#[inline(always)]
pub fn or_insert_with<F>(self, default: F) -> P::Output
where
F: FnOnce() -> P::Value,
{
match self {
Entry::Occupied(o) => o.into_value(),
Entry::Vacant(v) => v.insert(default()),
}
}
#[inline(always)]
pub fn or_insert_with_key<F>(self, default: F) -> P::Output
where
F: FnOnce(&[u8]) -> P::Value,
{
match self {
Entry::Occupied(o) => o.into_value(),
Entry::Vacant(v) => {
let value: P::Value = default(v.key());
v.insert(value)
}
}
}
pub fn or_default(self) -> P::Output
where
P::Value: Default,
{
self.or_insert(Default::default())
}
#[must_use]
pub fn and_modify<F>(self, f: F) -> Self
where
F: FnOnce(&P::Output) -> P::Value,
{
match self {
Entry::Occupied(mut o) => {
let new_value: P::Value = f(&o.value);
let new_output: P::Output = P::into_output(new_value);
let return_output: P::Output = new_output.clone();
let _old = o.tree.insert_output_with_guard(o.key, new_output, o.guard);
o.value = return_output;
Entry::Occupied(o)
}
Entry::Vacant(v) => Entry::Vacant(v),
}
}
#[inline]
pub fn insert_entry(self, value: P::Value) -> OccupiedEntry<'t, 'e, P, A> {
match self {
Entry::Occupied(mut o) => {
o.insert(value);
o
}
Entry::Vacant(v) => {
let key: &[u8] = v.key;
let tree: &MassTreeGeneric<P, A> = v.tree;
let guard: &LocalGuard<'_> = v.guard;
let output: P::Output = P::into_output(value);
let return_output: P::Output = output.clone();
let _old = tree.insert_output_with_guard(key, output, guard);
OccupiedEntry {
key,
value: return_output,
tree,
guard,
}
}
}
}
#[must_use]
#[inline(always)]
pub const fn get(&self) -> Option<&P::Output> {
match self {
Entry::Occupied(o) => Some(o.get()),
Entry::Vacant(_) => None,
}
}
}
impl<P, A> OccupiedEntry<'_, '_, P, A>
where
P: LeafPolicy,
A: TreeAllocator<P>,
{
#[must_use]
#[inline(always)]
pub const fn key(&self) -> &[u8] {
self.key
}
#[inline(always)]
pub const fn get(&self) -> &P::Output {
&self.value
}
#[inline(always)]
pub fn into_value(self) -> P::Output {
self.value
}
#[inline(always)]
pub fn insert(&mut self, value: P::Value) -> Option<P::Output> {
let output = P::into_output(value);
let old = self
.tree
.insert_output_with_guard(self.key, output.clone(), self.guard);
self.value = output;
old
}
#[inline(always)]
#[expect(
clippy::panic,
reason = "Convenience wrapper; use try_remove for fallible version"
)]
pub fn remove(self) -> Option<P::Output> {
match self.try_remove() {
Ok(value) => value,
Err(e) => panic!("OccupiedEntry::remove failed: {e:?}"),
}
}
#[inline(always)]
pub fn try_remove(self) -> Result<Option<P::Output>, RemoveError> {
self.tree.remove_with_guard(self.key, self.guard)
}
#[inline(always)]
#[expect(
clippy::panic,
reason = "Convenience wrapper; use try_remove_entry for fallible version"
)]
pub fn remove_entry(self) -> Option<(Vec<u8>, P::Output)> {
match self.try_remove_entry() {
Ok(result) => result,
Err(e) => panic!("OccupiedEntry::remove_entry failed: {e:?}"),
}
}
#[inline(always)]
pub fn try_remove_entry(self) -> RemoveEntryResult<P::Output> {
let key_owned: Vec<u8> = self.key.to_vec();
match self.tree.remove_with_guard(self.key, self.guard)? {
Some(value) => Ok(Some((key_owned, value))),
None => Ok(None),
}
}
}
impl<P, A> VacantEntry<'_, '_, P, A>
where
P: LeafPolicy,
A: TreeAllocator<P>,
{
#[must_use]
#[inline(always)]
pub const fn key(&self) -> &[u8] {
self.key
}
#[must_use]
#[inline(always)]
pub fn into_key(self) -> Vec<u8> {
self.key.to_vec()
}
#[inline(always)]
pub fn insert(self, value: P::Value) -> P::Output {
let output = P::into_output(value);
let return_output = output.clone();
let _old = self
.tree
.insert_output_with_guard(self.key, output, self.guard);
return_output
}
}
impl<P, A> Debug for Entry<'_, '_, P, A>
where
P: LeafPolicy,
P::Output: Send + Sync + Debug,
A: TreeAllocator<P>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> StdFmt::Result {
match self {
Entry::Occupied(o) => f.debug_tuple("Occupied").field(&o.value).finish(),
Entry::Vacant(v) => f.debug_tuple("Vacant").field(&v.key).finish(),
}
}
}
impl<P, A> Debug for OccupiedEntry<'_, '_, P, A>
where
P: LeafPolicy,
P::Output: Send + Sync + Debug,
A: TreeAllocator<P>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> StdFmt::Result {
f.debug_struct("OccupiedEntry")
.field("key", &self.key)
.field("value", &self.value)
.finish()
}
}
impl<P, A> Debug for VacantEntry<'_, '_, P, A>
where
P: LeafPolicy,
P::Output: Send + Sync + Debug,
A: TreeAllocator<P>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> StdFmt::Result {
f.debug_struct("VacantEntry")
.field("key", &self.key)
.finish()
}
}
impl<'t, 'e, P, A> Entry<'t, 'e, P, A>
where
P: LeafPolicy,
A: TreeAllocator<P>,
{
#[inline]
pub(crate) fn new(
tree: &'t MassTreeGeneric<P, A>,
key: &'e [u8],
guard: &'e LocalGuard<'t>,
) -> Self {
match tree.get_with_guard(key, guard) {
Some(value) => Entry::Occupied(OccupiedEntry {
key,
value,
tree,
guard,
}),
None => Entry::Vacant(VacantEntry { key, tree, guard }),
}
}
}
#[cfg(test)]
mod unit_tests;