use std::hash::Hash;
use lru::LruCache;
pub trait Cached<K, V> {
fn cache_get(&mut self, key: &K) -> Option<&V>;
fn cache_set(&mut self, key: K, val: V);
fn cache_remove(&mut self, k: &K) -> Option<V>;
fn cache_clear(&mut self);
fn cache_size(&self) -> usize;
fn cache_hits(&self) -> Option<u32>;
fn cache_misses(&self) -> Option<u32>;
}
#[derive(Debug)]
pub struct GrowableCache<K, V>
where
K: Eq + Hash,
{
store: LruCache<K, V>,
hits: u32,
misses: u32,
}
impl<K: Hash + Eq, V> GrowableCache<K, V> {
pub fn with_capacity(size: usize) -> Self {
Self {
store: LruCache::new(size),
hits: 0,
misses: 0,
}
}
}
impl<K: Hash + Eq, V> Cached<K, V> for GrowableCache<K, V> {
fn cache_get(&mut self, key: &K) -> Option<&V> {
#![allow(clippy::option_if_let_else)]
if let Some(v) = self.store.get(key) {
self.hits += 1;
Some(v)
} else {
self.misses += 1;
None
}
}
fn cache_set(&mut self, key: K, val: V) {
let _old_value = self.store.put(key, val);
}
fn cache_remove(&mut self, k: &K) -> Option<V> {
self.store.pop(k)
}
fn cache_clear(&mut self) {
self.store.clear();
}
fn cache_size(&self) -> usize {
self.store.len()
}
fn cache_hits(&self) -> Option<u32> {
Some(self.hits)
}
fn cache_misses(&self) -> Option<u32> {
Some(self.misses)
}
}
pub fn cache_info<K, V, C>(cache: &C) -> (usize, u32, f64)
where
C: Cached<K, V>,
{
if cache.cache_size() > 0 {
let hits = cache.cache_hits().unwrap_or(0);
let misses = cache.cache_misses().unwrap_or(0);
let hit_rate = if hits == 0 {
0.0
} else {
f64::from(hits) / f64::from(hits + misses)
};
(cache.cache_size(), hits, hit_rate)
} else {
(0, 0, 0.0)
}
}