This commit is contained in:
Valentin Brandl 2019-08-07 22:18:52 +02:00
parent 28296a0f6e
commit 1e806ef4f0
No known key found for this signature in database
GPG Key ID: 30D341DD34118D7D

View File

@ -1,9 +1,13 @@
//! Simple cache structure that stores values for a specified time. The cache itself is backed by
//! a HashMap.
use std::{ use std::{
collections::HashMap, collections::HashMap,
hash::Hash, hash::Hash,
time::{Duration, Instant}, time::{Duration, Instant},
}; };
/// Time based cache, that stores values for a defined time.
pub struct Cache<K, V> { pub struct Cache<K, V> {
cache: HashMap<K, CacheEntry<V>>, cache: HashMap<K, CacheEntry<V>>,
duration: Duration, duration: Duration,
@ -13,6 +17,16 @@ impl<K, V> Cache<K, V>
where where
K: Eq + Hash, K: Eq + Hash,
{ {
/// Creates a new cache.
///
/// # Example
/// ```
/// use std::time::Duration;
/// use time_cache::{Cache, CacheResult};
///
/// let cache: Cache<u8, u8> = Cache::new(Duration::from_secs(0));
/// assert_eq!(CacheResult::Empty, cache.get(&0));
/// ```
pub fn new(duration: Duration) -> Self { pub fn new(duration: Duration) -> Self {
Self { Self {
cache: HashMap::new(), cache: HashMap::new(),
@ -20,6 +34,20 @@ where
} }
} }
/// Get an item from the cache. The item can be either valid, invalid or non existent.
///
/// # Example
/// ```
/// use std::time::Duration;
/// use time_cache::{Cache, CacheResult};
///
/// let key = 0;
/// let value = 1;
/// let mut cache: Cache<u8, u8> = Cache::new(Duration::from_secs(0));
/// assert_eq!(CacheResult::Empty, cache.get(&key));
/// cache.store(key, value);
/// assert_eq!(CacheResult::Invalid, cache.get(&key));
/// ```
pub fn get(&self, key: &K) -> CacheResult<&V> { pub fn get(&self, key: &K) -> CacheResult<&V> {
if let Some(entry) = self.cache.get(key) { if let Some(entry) = self.cache.get(key) {
if Self::is_valid(Instant::now(), entry) { if Self::is_valid(Instant::now(), entry) {
@ -32,16 +60,66 @@ where
} }
} }
/// Removes an item from the cache. Returns `true` if the key was present.
///
/// # Example
/// ```
/// use std::time::Duration;
/// use time_cache::{Cache, CacheResult};
///
/// let key = 0;
/// let value = 1;
/// let mut cache: Cache<u8, u8> = Cache::new(Duration::from_secs(0));
/// assert!(!cache.invalidate(&key));
/// cache.store(key, value);
/// assert!(cache.invalidate(&key));
/// ```
pub fn invalidate(&mut self, key: &K) -> bool { pub fn invalidate(&mut self, key: &K) -> bool {
self.cache.remove(key).is_some() self.cache.remove(key).is_some()
} }
/// Stores an item in the cache.
///
/// # Example
/// ```
/// use std::time::Duration;
/// use time_cache::{Cache, CacheResult};
///
/// let key = 0;
/// let value = 1;
/// let dur = Duration::from_millis(500);
/// let mut cache: Cache<u8, u8> = Cache::new(dur);
///
/// assert_eq!(CacheResult::Empty, cache.get(&key));
/// cache.store(key, value);
/// assert_eq!(CacheResult::Cached(&value), cache.get(&key));
/// std::thread::sleep(dur);
/// assert_eq!(CacheResult::Invalid, cache.get(&key));
/// ```
pub fn store(&mut self, key: K, value: V) -> Option<V> { pub fn store(&mut self, key: K, value: V) -> Option<V> {
self.cache self.cache
.insert(key, CacheEntry::new(value, self.duration)) .insert(key, CacheEntry::new(value, self.duration))
.map(|old| old.1) .map(|old| old.1)
} }
/// Removes all invalid items from the cache.
///
/// # Example
/// ```
/// use std::time::Duration;
/// use time_cache::{Cache, CacheResult};
///
/// let key = 0;
/// let value = 1;
/// let dur = Duration::from_secs(0);
/// let mut cache: Cache<u8, u8> = Cache::new(dur);
///
/// assert_eq!(CacheResult::Empty, cache.get(&key));
/// cache.store(key, value);
/// assert_eq!(CacheResult::Invalid, cache.get(&key));
/// cache.clear();
/// assert_eq!(CacheResult::Empty, cache.get(&key));
/// ```
pub fn clear(&mut self) { pub fn clear(&mut self) {
let now = Instant::now(); let now = Instant::now();
self.cache.retain(|_, v| Self::is_valid(now, v)) self.cache.retain(|_, v| Self::is_valid(now, v))
@ -52,9 +130,14 @@ where
} }
} }
/// Result when requesting a cached item.
#[derive(Debug, PartialEq)]
pub enum CacheResult<T> { pub enum CacheResult<T> {
/// Item is cached and still valid
Cached(T), Cached(T),
/// Item is cached but invalid
Invalid, Invalid,
/// Item is not in the cache
Empty, Empty,
} }