#[cfg(feature = "dev-tools")]
use indexmap::IndexMap;
#[cfg(feature = "dev-tools")]
use std::collections::HashMap;
#[cfg(feature = "dev-tools")]
use std::hash::Hash;
#[cfg(feature = "dev-tools")]
use std::time::{Duration, Instant};
#[cfg(feature = "dev-tools")]
#[derive(Debug)]
pub struct LruCache<K, V>
where
K: Eq + Hash + Clone,
{
capacity: usize,
map: IndexMap<K, V>,
}
#[cfg(feature = "dev-tools")]
impl<K, V> LruCache<K, V>
where
K: Eq + Hash + Clone,
{
pub fn new(capacity: usize) -> Self {
assert!(capacity > 0, "LruCache capacity must be greater than 0");
Self {
capacity,
map: IndexMap::new(),
}
}
pub fn insert(&mut self, key: K, value: V) {
if self.map.contains_key(&key) {
self.map.shift_remove(&key);
} else if self.map.len() >= self.capacity {
self.map.shift_remove_index(0);
}
self.map.insert(key, value);
}
pub fn get(&mut self, key: &K) -> Option<&V> {
if self.map.contains_key(key) {
let value = self.map.shift_remove(key)?;
self.map.insert(key.clone(), value);
self.map.get(key)
} else {
None
}
}
pub fn remove(&mut self, key: &K) -> Option<V> {
self.map.shift_remove(key)
}
pub fn clear(&mut self) {
self.map.clear();
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
}
#[cfg(feature = "dev-tools")]
#[derive(Debug, Clone)]
struct TtlEntry<V> {
value: V,
expires_at: Instant,
}
#[cfg(feature = "dev-tools")]
#[derive(Debug)]
pub struct TtlCache<K, V>
where
K: Eq + Hash + Clone,
{
ttl: Duration,
map: HashMap<K, TtlEntry<V>>,
}
#[cfg(feature = "dev-tools")]
impl<K, V> TtlCache<K, V>
where
K: Eq + Hash + Clone,
{
pub fn new(ttl: Duration) -> Self {
Self {
ttl,
map: HashMap::new(),
}
}
pub fn insert(&mut self, key: K, value: V) {
let entry = TtlEntry {
value,
expires_at: Instant::now() + self.ttl,
};
self.map.insert(key, entry);
}
pub fn get(&mut self, key: &K) -> Option<&V> {
self.cleanup_expired();
self.map.get(key).map(|entry| &entry.value)
}
pub fn remove(&mut self, key: &K) -> Option<V> {
self.map.remove(key).map(|entry| entry.value)
}
pub fn cleanup_expired(&mut self) {
let now = Instant::now();
self.map.retain(|_, entry| entry.expires_at > now);
}
pub fn clear(&mut self) {
self.map.clear();
}
pub fn len(&self) -> usize {
self.map.len()
}
pub fn is_empty(&self) -> bool {
self.map.is_empty()
}
}
#[cfg(feature = "dev-tools")]
#[derive(Debug, Clone, Default)]
pub struct CacheStats {
pub hits: u64,
pub misses: u64,
pub evictions: u64,
pub insertions: u64,
}
#[cfg(feature = "dev-tools")]
impl CacheStats {
pub fn new() -> Self {
Self::default()
}
pub fn hit_rate(&self) -> f64 {
let total = self.hits + self.misses;
if total == 0 {
0.0
} else {
self.hits as f64 / total as f64
}
}
pub fn record_hit(&mut self) {
self.hits += 1;
}
pub fn record_miss(&mut self) {
self.misses += 1;
}
pub fn record_eviction(&mut self) {
self.evictions += 1;
}
pub fn record_insertion(&mut self) {
self.insertions += 1;
}
}