reslab 0.0.0

`HashMap` alternative, backed with slab storage.
Documentation
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};

/// A type that represents an entry in a slab.
pub enum Entry<'a, K: Key, V, S> {
    Vacant(VacantEntry<'a, K, V, S>),
    Occupied(OccupiedEntry<'a, K, V, S>),
}

/// A type that represents a vacant entry in a slab.
pub struct VacantEntry<'a, K: Key, V, S> {
    idxs: DashVacantEntry<'a, K, usize, S>,
    slab: &'a Slab<V>,
}

/// A type that represents an occupied entry in a slab.
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,
{
    /// Creates a new instance of [`Entry`] from the provided key.
    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))
            }
        }
    }

    /// Tries to insert the provided value into the slab, returning the
    /// [`Some(Index<T>)`] of the inserted value if successful.
    #[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),
        }
    }

    /// Tries to insert the value returned by the provided closure into the
    /// slab, returning the [`Some(Index<T>)`] of the inserted value if
    /// successful.
    #[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()),
        }
    }

    /// Tries to insert a default value of `V` into the slab, returning the
    /// [`Some(Index<T>)`] of the inserted value if successful.
    #[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,
{
    /// Creates a new instance of [`VacantEntry`].
    #[inline]
    pub(super) const fn new(
        idxs: DashVacantEntry<'a, K, usize, S>,
        slab: &'a Slab<V>,
    ) -> Self {
        Self { idxs, slab }
    }

    /// Inserts the provided value into the slab, returning the index of the
    /// inserted value.
    #[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()))
    }

    /// Gets the key for this entry.
    #[inline]
    pub fn key(&self) -> &K {
        self.idxs.key()
    }
}

impl<'a, K: Key, V, S> OccupiedEntry<'a, K, V, S>
where
    S: BuildHasher + Clone,
{
    /// Creates a new instance of [`OccupiedEntry`].
    #[inline]
    pub(super) const fn new(
        idxs_entry: DashOccupiedEntry<'a, K, usize, S>,
        slab_entry: SlabEntry<'a, V>,
    ) -> Self {
        Self {
            idxs_entry,
            slab_entry,
        }
    }

    /// Gets the key for this entry.
    #[inline]
    pub fn key(&self) -> &K {
        self.idxs_entry.key()
    }

    /// Gets the offset of the value in the slab.
    #[inline]
    pub fn offset(&self) -> usize {
        *self.idxs_entry.get()
    }

    /// Gets the index of the value in the slab.
    #[inline]
    pub fn index(&self) -> Index<K, V> {
        Index::new(*self.idxs_entry.key(), *self.idxs_entry.get())
    }

    /// Gets a reference to the value for this entry.
    #[inline]
    pub fn get(&self) -> &V {
        self.slab_entry.deref()
    }

    /// Removes the link to this entry from the indeces map, returning the
    /// offset of the value in the slab.
    ///
    /// # Safety
    /// This does not remove the value from the slab. The actual value **must**
    /// be removed from the slab manually
    #[inline]
    pub unsafe fn unlink(self) -> usize {
        self.idxs_entry.remove()
    }
}