use lru::LruCache;
use std::num::NonZeroUsize;
use tokio::sync::RwLock;
pub trait Expired {
fn is_expired(&self) -> bool;
}
pub struct TtlLruStore<T> {
cache: RwLock<LruCache<String, T>>,
}
impl<T: Expired + Clone> TtlLruStore<T> {
pub fn new(size: NonZeroUsize) -> Self {
Self {
cache: RwLock::new(LruCache::new(size)),
}
}
pub async fn set(&self, key: &str, value: T) {
let mut cache = self.cache.write().await;
cache.put(key.to_string(), value);
}
pub async fn get(&self, key: &str) -> Option<T> {
let cache = self.cache.read().await;
cache.peek(key).filter(|v| !v.is_expired()).cloned()
}
pub async fn del(&self, key: &str) {
let mut cache = self.cache.write().await;
cache.pop(key);
}
pub async fn purge_expired(&self) {
let mut cache = self.cache.write().await;
let keys: Vec<String> = cache
.iter()
.filter(|(_, v)| v.is_expired())
.map(|(k, _)| k.clone())
.collect();
for key in keys {
cache.pop(&key);
}
}
}