use lru::LruCache;
use std::convert::Infallible;
use std::hash::Hash;
use std::sync::Mutex;
pub struct SyncLruCache<K, V> {
inner: Mutex<LruCache<K, V>>,
}
impl<K, V> SyncLruCache<K, V>
where
K: Hash + Eq,
V: Clone,
{
pub fn new(cap: usize) -> Self {
Self { inner: Mutex::new(LruCache::<K, V>::new(cap)) }
}
pub fn len(&self) -> usize {
self.inner.lock().unwrap().len()
}
pub fn is_empty(&self) -> bool {
self.inner.lock().unwrap().is_empty()
}
pub fn get_or_put<F>(&self, key: K, f: F) -> V
where
V: Clone,
F: FnOnce(&K) -> V,
{
Result::<_, Infallible>::unwrap(self.get_or_try_put(key, |k| Ok(f(k))))
}
pub fn get_or_try_put<F, E>(&self, key: K, f: F) -> Result<V, E>
where
V: Clone,
F: FnOnce(&K) -> Result<V, E>,
{
if let Some(result) = self.get(&key) {
return Ok(result);
}
let val = f(&key)?;
let val_clone = val.clone();
self.inner.lock().unwrap().put(key, val_clone);
Ok(val)
}
pub fn put(&self, key: K, value: V) {
self.inner.lock().unwrap().put(key, value);
}
pub fn get(&self, key: &K) -> Option<V> {
self.inner.lock().unwrap().get(key).cloned()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_cache() {
let cache = SyncLruCache::<u64, Vec<u64>>::new(100);
assert_eq!(cache.get(&0u64), None);
assert_eq!(cache.get_or_put(123u64, |key| vec![*key, 123]), vec![123u64, 123]);
assert_eq!(cache.get(&123u64), Some(vec![123u64, 123]));
assert_eq!(cache.get(&0u64), None);
}
}