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 {
let cache: LruCache<String, T> = LruCache::new(size);
TtlLruStore {
cache: RwLock::new(cache),
}
}
pub async fn set(&self, key: &str, value: T) {
let cache = &mut 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;
let v = cache.peek(key)?;
if !v.is_expired() {
return Some(v.clone());
}
None
}
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_to_remove: Vec<String> = cache
.iter()
.filter(|(_, v)| v.is_expired())
.map(|(k, _)| k.clone())
.collect();
if keys_to_remove.is_empty() {
return;
}
for key in keys_to_remove {
cache.pop(&key);
}
}
}