lru-cache-map 0.2.0

A cache that holds a limited number of key-value pairs.
Documentation
use std::fmt::Debug;
use std::fmt::Formatter;
use std::hash::BuildHasher;
use std::hash::Hash;
use std::ops::Deref;
use std::ops::DerefMut;

use hashlink::linked_hash_map::RawOccupiedEntryMut;

use crate::meter::Meter;
use crate::LruCache;

/// A wrapper that `deref` or `deref_mut` to a mutable reference to the value corresponding to a
/// given key in a cache.
///
/// When this structure is dropped, the cache [`Meter`] will be updated by the new value and if the
/// [`size()`] exceeds the [`capacity()`], the least recently used items will be evicted.
///
/// [`size()`]: crate::LruCache::size
/// [`capacity()`]: crate::LruCache::capacity
pub struct PeekMut<'a, K, V, S, M>
where
    K: Eq + Hash,
    S: BuildHasher,
    M: Meter<K, V>,
{
    entry: RawOccupiedEntryMut<'a, K, V>,
    lru: *mut LruCache<K, V, S, M>,
}

impl<'a, K, V, S, M> PeekMut<'a, K, V, S, M>
where
    K: Eq + Hash,
    S: BuildHasher,
    M: Meter<K, V>,
{
    pub(crate) fn new(
        entry: RawOccupiedEntryMut<'a, K, V>,
        lru: *mut LruCache<K, V, S, M>,
    ) -> Self {
        let lru = unsafe { &mut *lru };

        lru.measure_remove(entry.key(), entry.get());

        PeekMut { entry, lru }
    }
}

impl<'a, K, V, S, M> Debug for PeekMut<'a, K, V, S, M>
where
    K: Eq + Hash,
    V: Debug,
    S: BuildHasher,
    M: Meter<K, V>,
{
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        f.debug_tuple("PeekMut").field(&self.deref()).finish()
    }
}

impl<'a, K, V, S, M> Deref for PeekMut<'a, K, V, S, M>
where
    K: Eq + Hash,
    S: BuildHasher,
    M: Meter<K, V>,
{
    type Target = V;

    fn deref(&self) -> &Self::Target {
        self.entry.get()
    }
}

impl<'a, K, V, S, M> DerefMut for PeekMut<'a, K, V, S, M>
where
    K: Eq + Hash,
    S: BuildHasher,
    M: Meter<K, V>,
{
    fn deref_mut(&mut self) -> &mut Self::Target {
        self.entry.get_mut()
    }
}

impl<'a, K, V, S, M> Drop for PeekMut<'a, K, V, S, M>
where
    K: Eq + Hash,
    S: BuildHasher,
    M: Meter<K, V>,
{
    fn drop(&mut self) {
        let lru = unsafe { &mut *self.lru };
        lru.measure_add(self.entry.key(), self.entry.get());

        lru.evict_by_policy();
    }
}