use super::*;
use std::fmt;
pub struct Entry<'a, K, V, C, I, R>
where
C: Capacity,
R: Replacement<V, C>,
{
pub(crate) cache: &'a mut AssociativeCache<K, V, C, I, R>,
pub(crate) index: usize,
pub(crate) kind: EntryKind,
}
impl<'a, K, V, C, I, R> fmt::Debug for Entry<'a, K, V, C, I, R>
where
C: Capacity,
R: Replacement<V, C>,
{
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let Entry {
cache: _,
ref index,
ref kind,
} = self;
f.debug_struct("Entry")
.field("index", index)
.field("kind", kind)
.finish()
}
}
#[derive(Debug)]
pub(crate) enum EntryKind {
Occupied,
Vacant,
Replace,
}
impl<'a, K, V, C, I, R> Entry<'a, K, V, C, I, R>
where
C: Capacity,
I: Indices<K, C>,
R: Replacement<V, C>,
{
#[inline]
pub fn or_insert_with(
self,
make_key: impl FnOnce() -> K,
make_val: impl FnOnce() -> V,
) -> &'a mut V {
assert!(self.index < C::CAPACITY);
match self.kind {
EntryKind::Occupied => match &mut self.cache.entries[self.index] {
Some((_, v)) => v,
_ => unreachable!(),
},
EntryKind::Vacant | EntryKind::Replace => {
if let EntryKind::Vacant = self.kind {
self.cache.len += 1;
}
self.cache.entries[self.index] = Some((make_key(), make_val()));
match &mut self.cache.entries[self.index] {
Some((_, v)) => {
self.cache.replacement_policy.on_insert(v);
v
}
_ => unreachable!(),
}
}
}
}
#[inline]
pub fn take_entry_that_will_be_replaced(&mut self) -> Option<(K, V)> {
assert!(self.index < C::CAPACITY);
if let EntryKind::Replace = self.kind {
self.cache.len -= 1;
self.kind = EntryKind::Vacant;
mem::replace(&mut self.cache.entries[self.index], None)
} else {
None
}
}
}