use crate::id::index_of;
struct Entry<K, V> {
key: K,
value: V,
}
pub(crate) struct BoundedStore<K, V> {
ceiling: u32,
entries: Vec<Entry<K, V>>,
}
impl<K: PartialEq, V: Clone> BoundedStore<K, V> {
pub(crate) fn new(ceiling: u32) -> Self {
Self {
ceiling,
entries: Vec::new(),
}
}
pub(crate) fn get(&mut self, key: &K) -> Option<V> {
self.selected(key, |_| true)
}
pub(crate) fn selected(&mut self, key: &K, states: impl Fn(&V) -> bool) -> Option<V> {
let found = self
.entries
.iter()
.rposition(|entry| entry.key == *key && states(&entry.value))?;
let entry = self.entries.remove(found);
let value = entry.value.clone();
self.entries.push(entry);
Some(value)
}
pub(crate) fn retain(&mut self, key: K, value: V) -> u64 {
self.discard(&key);
let evicted = self.evict_beyond(self.ceiling.saturating_sub(1));
match self.ceiling {
0 => evicted,
_ => {
self.entries.push(Entry { key, value });
evicted
}
}
}
fn discard(&mut self, key: &K) {
self.entries.retain(|entry| entry.key != *key);
}
fn evict_beyond(&mut self, remaining: u32) -> u64 {
let kept = index_of(remaining);
let evicted = self.entries.len().saturating_sub(kept);
self.entries.drain(..evicted);
u64::try_from(evicted).unwrap_or(u64::MAX)
}
pub(crate) fn clear(&mut self) {
self.entries.clear();
}
}