use std::collections::HashMap;
use tokio::sync::RwLock;
use std::hash::Hash;
use std::time::{Duration, Instant};
#[derive(Clone)]
pub struct Item<T> {
pub object: T,
expiry: Option<Instant>,
}
impl<T> Item<T> {
pub fn new(object: T, item_duration: Option<Duration>) -> Self {
let expiry = item_duration.map(|duration| Instant::now() + duration);
Item { object, expiry }
}
pub fn expired(&self) -> bool {
self.expiry
.map(|expiry| expiry < Instant::now())
.unwrap_or(false)
}
}
pub struct Cache<T, V> {
items: RwLock<HashMap<T, Item<V>>>,
}
impl<T, V> Cache<T, V> {
pub fn new() -> Self {
Cache {
items: RwLock::new(HashMap::new()),
}
}
pub async fn get(&self, key: &T) -> Option<V>
where
T: Eq + Hash,
V: Clone,
{
self.items
.read()
.await
.get(key)
.filter(|item| !item.expired())
.map(|item| item.object.clone())
}
pub async fn set(&self, key: T, value: V, custom_duration: Option<Duration>) -> Option<V>
where
T: Eq + Hash,
{
self.items
.write()
.await
.insert(key, Item::new(value, custom_duration))
.map(|item| item.object)
}
pub async fn remove_expired(&self)
where
T: Eq + Hash + Clone,
{
let expired_keys = self
.items
.read()
.await
.iter()
.filter(|(_, item)| item.expired())
.map(|(k, _)| k.clone())
.collect::<Vec<T>>();
for key in expired_keys {
self.items.write().await.remove(&key);
}
}
pub async fn remove(&self, key: &T) -> Option<V>
where
T: Eq + Hash,
{
self.items.write().await.remove(key).map(|item| item.object)
}
pub async fn clear(&self) {
self.items.write().await.clear()
}
}