Created
December 30, 2014 18:56
-
-
Save archer884/6a80c5a9da6fdbd246e4 to your computer and use it in GitHub Desktop.
Rust cache with expiring items
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
extern crate chrono; | |
pub mod expiring_cache { | |
use chrono::{DateTime, Duration, UTC}; | |
use std::collections::HashMap; | |
use std::collections::hash_map::Entry::{Occupied, Vacant}; | |
use std::hash::Hash; | |
pub struct ExpiringCache<Key, Value> where Key: Eq + Hash { | |
expiry: Duration, // cache endurance | |
cache: HashMap<Key, Timestamped<Value>>, // hashmap containing references to cached items | |
} | |
impl<Key, Value> ExpiringCache<Key, Value> where Key: Copy + Eq + Hash { | |
pub fn new(expiry: Duration) -> ExpiringCache<Key, Value> { | |
ExpiringCache { | |
expiry: expiry, | |
cache: HashMap::new(), | |
} | |
} | |
pub fn get(&mut self, key: Key, fallback: |k: &Key| -> Value) -> &Value { | |
match self.cache.entry(key) { | |
Occupied(mut entry) => { | |
if UTC::now() - entry.get().t.clone() > self.expiry { | |
entry.set(Timestamped::new(fallback(&key))); | |
} | |
}, | |
Vacant(entry) => { | |
entry.set(Timestamped::new(fallback(&key))); | |
} | |
}; | |
&*self.cache[key].value | |
} | |
} | |
struct Timestamped<Value> { | |
t: DateTime<UTC>, | |
value: Box<Value>, | |
} | |
impl<Value> Timestamped<Value> { | |
fn new(value: Value) -> Timestamped<Value> { | |
Timestamped { | |
t: UTC::now(), | |
value: box value, | |
} | |
} | |
} | |
#[cfg(test)] | |
mod test{ | |
use expiring_cache::ExpiringCache; | |
use std::io::timer; | |
use std::time::Duration; | |
#[test] | |
fn it_works_at_all() { | |
let mut cache = ExpiringCache::new(Duration::seconds(3)); | |
assert!(9u == *cache.get(3u, |key| *key * 3)); | |
} | |
#[test] | |
fn cache_entries_expire() { | |
let mut cache = ExpiringCache::new(Duration::seconds(3)); | |
let mut count = 0u; | |
assert!(9u == *cache.get(3u, |key| { count += 1; *key * 3 })); | |
assert!(9u == *cache.get(3u, |key| { count += 1; *key * 3 })); | |
timer::sleep(Duration::milliseconds(3100)); | |
assert!(9u == *cache.get(3u, |key| { count += 1; *key * 3 })); | |
assert!(2u == count); | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment