use std::hash::{BuildHasher, Hash};
use crate::ExtractKey;
use super::ExtractMap;
use hashbrown::hash_table::{
Entry as RawEntry, OccupiedEntry as RawOccupiedEntry, VacantEntry as RawVacantEntry,
};
macro_rules! forward_debug {
($type_name:ident) => {
impl<'a, V: std::fmt::Debug> std::fmt::Debug for $type_name<'a, V> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
};
}
impl<K, V, S> ExtractMap<K, V, S>
where
K: Hash + Eq,
V: ExtractKey<K>,
S: BuildHasher,
{
pub fn entry(&mut self, key: &K) -> Entry<'_, V> {
Entry::from_raw(self.raw_entry(key))
}
}
#[derive(Debug)]
pub enum Entry<'a, V> {
Occupied(OccupiedEntry<'a, V>),
Vacant(VacantEntry<'a, V>),
}
impl<'a, V> Entry<'a, V> {
fn from_raw(raw: RawEntry<'a, V>) -> Self {
match raw {
RawEntry::Occupied(raw_entry) => Entry::Occupied(OccupiedEntry(raw_entry)),
RawEntry::Vacant(raw_entry) => Entry::Vacant(VacantEntry(raw_entry)),
}
}
fn into_raw(self) -> RawEntry<'a, V> {
match self {
Entry::Occupied(entry) => RawEntry::Occupied(entry.0),
Entry::Vacant(entry) => RawEntry::Vacant(entry.0),
}
}
pub fn insert(self, value: V) -> OccupiedEntry<'a, V> {
OccupiedEntry(self.into_raw().insert(value))
}
pub fn or_insert(self, default: V) -> OccupiedEntry<'a, V> {
OccupiedEntry(self.into_raw().or_insert(default))
}
pub fn or_insert_with(self, default: impl FnOnce() -> V) -> OccupiedEntry<'a, V> {
OccupiedEntry(self.into_raw().or_insert_with(default))
}
#[allow(clippy::return_self_not_must_use)]
pub fn and_modify(self, f: impl FnOnce(&mut V)) -> Self {
Self::from_raw(self.into_raw().and_modify(f))
}
}
pub struct OccupiedEntry<'a, V>(RawOccupiedEntry<'a, V>);
forward_debug!(OccupiedEntry);
impl<'a, V> OccupiedEntry<'a, V> {
#[allow(clippy::must_use_candidate)]
pub fn remove(self) -> V {
self.0.remove().0
}
#[must_use]
pub fn get(&self) -> &V {
self.0.get()
}
pub fn get_mut(&mut self) -> &mut V {
self.0.get_mut()
}
#[must_use]
pub fn into_mut(self) -> &'a mut V {
self.0.into_mut()
}
pub fn insert(&mut self, value: V) -> V {
std::mem::replace(self.0.get_mut(), value)
}
}
pub struct VacantEntry<'a, V>(RawVacantEntry<'a, V>);
forward_debug!(VacantEntry);
impl<'a, V> VacantEntry<'a, V> {
pub fn insert(self, value: V) -> OccupiedEntry<'a, V> {
OccupiedEntry(self.0.insert(value))
}
}