Skip to content

Instantly share code, notes, and snippets.

@archer884
Created December 30, 2014 18:56
Show Gist options
  • Save archer884/6a80c5a9da6fdbd246e4 to your computer and use it in GitHub Desktop.
Save archer884/6a80c5a9da6fdbd246e4 to your computer and use it in GitHub Desktop.
Rust cache with expiring items
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