use std::collections::HashMap;
use std::fmt::Debug;
use std::hash::Hash;
use std::time::{Duration, Instant};
#[derive(Debug, Clone)]
struct Entry<V> {
value: V,
insert_time: Instant,
}
#[derive(Debug, Clone)]
pub struct SimpleCache<K, V> {
hashmap: HashMap<K, Entry<V>>,
timeout: Option<Duration>,
}
impl<K: Eq + Hash + Clone + Debug, V: Clone + Debug> SimpleCache<K, V> {
pub fn new(timeout: Option<Duration>) -> SimpleCache<K, V> {
SimpleCache {
hashmap: HashMap::new(),
timeout,
}
}
pub fn get(&mut self, key: &K) -> Option<V> {
let entry = self.hashmap.get(key)?;
if let Some(timeout) = self.timeout {
if entry.insert_time.elapsed() >= timeout {
self.delete(key);
return None;
}
}
Some(entry.value.clone())
}
pub fn keys(&self) -> Vec<K> {
self.hashmap.keys().map(|k| k.clone()).collect::<Vec<K>>()
}
pub fn values(&self) -> Vec<V> {
self.hashmap
.values()
.map(|v| v.value.clone())
.collect::<Vec<V>>()
}
pub fn tuples(&self) -> Vec<(K, V)> {
self.hashmap.iter()
.map(|(k, v)| (k.clone(), v.value.clone()))
.collect::<Vec<(K, V)>>()
}
pub fn insert_batch(&mut self, items: Vec<(K, V)>) {
let i_now = Instant::now();
for item in items {
self.hashmap.insert(
item.0,
Entry {
value: item.1,
insert_time: i_now,
},
);
}
}
pub fn insert(&mut self, key: K, value: V) -> Option<V> {
self.hashmap
.insert(
key,
Entry {
value,
insert_time: Instant::now(),
},
)
.map(|entry| entry.value)
}
pub fn delete(&mut self, key: &K) -> Option<V> {
self.hashmap.remove(key).map(|entry| entry.value)
}
}
#[cfg(test)]
mod tests {
use super::SimpleCache;
use std::{thread, time::Duration};
#[test]
fn insert_and_get_item() {
let mut scache: SimpleCache<i32, String> = SimpleCache::new(None);
scache.insert(1, String::from("hello"));
let v = scache.get(&1);
assert_eq!(Some(String::from("hello")), v)
}
#[test]
fn insert_and_get_item_and_remove() {
let mut scache: SimpleCache<i32, String> = SimpleCache::new(None);
scache.insert(1, String::from("hello"));
let v = scache.get(&1);
assert_eq!(Some(String::from("hello")), v);
scache.delete(&1);
let no_value = scache.get(&1);
assert_eq!(None, no_value)
}
#[test]
fn insert_batch_test() {
let mut scache: SimpleCache<i32, String> = SimpleCache::new(None);
scache.insert_batch(vec![(1, String::from("hello")), (2, String::from("world"))]);
let values = scache.values();
assert!(values.contains(&&String::from("hello")));
assert!(values.contains(&&String::from("world")))
}
#[test]
fn get_keys_test() {
let mut scache: SimpleCache<i32, String> = SimpleCache::new(None);
scache.insert(1, String::from("hello"));
let keys = scache.keys();
assert_eq!(keys, vec!(1))
}
#[test]
fn get_values_test() {
let mut scache: SimpleCache<i32, String> = SimpleCache::new(None);
scache.insert(1, String::from("hello"));
let values = scache.values();
assert_eq!(values, vec!("hello"))
}
#[test]
fn insert_with_timeout() {
let timeout = Duration::new(1, 0);
let mut scache: SimpleCache<i32, String> = SimpleCache::new(Some(timeout));
scache.insert(1, String::from("hello"));
thread::sleep(Duration::new(1, 1));
let v = scache.get(&1);
assert_eq!(None, v)
}
#[test]
fn get_tuples_test() {
let mut scache: SimpleCache<i32, String> = SimpleCache::new(None);
scache.insert(1, String::from("hello"));
let values: Vec<(i32, String)> = scache.tuples();
assert_eq!(values, vec!((1, String::from("hello"))))
}
}