use std::{hash::BuildHasher, ops::Deref};
use dashmap::{
mapref::entry::{
Entry as DashEntry,
OccupiedEntry as DashOccupiedEntry,
VacantEntry as DashVacantEntry,
},
DashMap,
};
use sharded_slab::{Entry as SlabEntry, Slab};
use crate::{Index, Key};
pub enum Entry<'a, K: Key, V, S> {
Vacant(VacantEntry<'a, K, V, S>),
Occupied(OccupiedEntry<'a, K, V, S>),
}
pub struct VacantEntry<'a, K: Key, V, S> {
idxs: DashVacantEntry<'a, K, usize, S>,
slab: &'a Slab<V>,
}
pub struct OccupiedEntry<'a, K: Key, V, S> {
idxs_entry: DashOccupiedEntry<'a, K, usize, S>,
slab_entry: SlabEntry<'a, V>,
}
impl<'a, K: Key, V, S> Entry<'a, K, V, S>
where
S: BuildHasher + Clone,
{
pub(super) fn new(
key: K,
idxs: &'a DashMap<K, usize, S>,
slab: &'a Slab<V>,
) -> Self {
match idxs.entry(key) {
| DashEntry::Vacant(e) => Self::Vacant(VacantEntry::new(e, slab)),
| DashEntry::Occupied(e) => {
let slab_entry = slab.get(*e.get()).expect(
"BUG: slab entries should always exists if the index \
exists in the index map",
);
Self::Occupied(OccupiedEntry::new(e, slab_entry))
}
}
}
#[inline]
pub fn or_try_insert(self, value: V) -> Option<Index<K, V>> {
match self {
| Self::Occupied(entry) => Some(entry.index()),
| Self::Vacant(entry) => entry.try_insert(value),
}
}
#[inline]
pub fn or_try_insert_with(
self,
f: impl FnOnce() -> V,
) -> Option<Index<K, V>> {
match self {
| Self::Occupied(entry) => Some(entry.index()),
| Self::Vacant(entry) => entry.try_insert(f()),
}
}
#[inline]
pub fn or_try_insert_default(self) -> Option<Index<K, V>>
where
V: Default,
{
self.or_try_insert_with(V::default)
}
}
impl<'a, K: Key, V, S> VacantEntry<'a, K, V, S>
where
S: BuildHasher + Clone,
{
#[inline]
pub(super) const fn new(
idxs: DashVacantEntry<'a, K, usize, S>,
slab: &'a Slab<V>,
) -> Self {
Self { idxs, slab }
}
#[inline]
pub fn try_insert(self, value: V) -> Option<Index<K, V>>
where
Self: 'a,
{
let idx = match self.slab.insert(value) {
| Some(slab_idx) => self.idxs.insert(slab_idx),
| None => return None,
};
Some(Index::new(*idx.key(), *idx.value()))
}
#[inline]
pub fn key(&self) -> &K {
self.idxs.key()
}
}
impl<'a, K: Key, V, S> OccupiedEntry<'a, K, V, S>
where
S: BuildHasher + Clone,
{
#[inline]
pub(super) const fn new(
idxs_entry: DashOccupiedEntry<'a, K, usize, S>,
slab_entry: SlabEntry<'a, V>,
) -> Self {
Self {
idxs_entry,
slab_entry,
}
}
#[inline]
pub fn key(&self) -> &K {
self.idxs_entry.key()
}
#[inline]
pub fn offset(&self) -> usize {
*self.idxs_entry.get()
}
#[inline]
pub fn index(&self) -> Index<K, V> {
Index::new(*self.idxs_entry.key(), *self.idxs_entry.get())
}
#[inline]
pub fn get(&self) -> &V {
self.slab_entry.deref()
}
#[inline]
pub unsafe fn unlink(self) -> usize {
self.idxs_entry.remove()
}
}