ferron_common/util/
ttl_cache.rs1use std::collections::HashMap;
2use std::time::{Duration, Instant};
3
4pub struct TtlCache<K, V> {
6 cache: HashMap<K, (V, Instant)>,
7 ttl: Duration,
8}
9
10impl<K, V> TtlCache<K, V>
11where
12 K: std::cmp::Eq + std::hash::Hash + Clone,
13 V: Clone,
14{
15 pub fn new(ttl: Duration) -> Self {
17 Self {
18 cache: HashMap::new(),
19 ttl,
20 }
21 }
22
23 pub fn insert(&mut self, key: K, value: V) {
25 self.cache.insert(key, (value, Instant::now()));
26 }
27
28 pub fn get(&self, key: &K) -> Option<V> {
30 self.cache.get(key).and_then(|(value, timestamp)| {
31 if timestamp.elapsed() < self.ttl {
32 Some(value.clone())
33 } else {
34 None
35 }
36 })
37 }
38
39 #[allow(dead_code)]
41 pub fn remove(&mut self, key: &K) -> Option<V> {
42 self.cache.remove(key).map(|(value, _)| value)
43 }
44
45 pub fn cleanup(&mut self) {
47 self.cache.retain(|_, (_, timestamp)| timestamp.elapsed() < self.ttl);
48 }
49}
50
51#[cfg(test)]
52mod tests {
53 use super::*;
54 use std::thread::sleep;
55 use std::time::Duration;
56
57 #[test]
58 fn test_insert_and_get() {
59 let mut cache = TtlCache::new(Duration::new(5, 0));
60 cache.insert("key1", "value1");
61
62 assert_eq!(cache.get(&"key1"), Some("value1"));
63 }
64
65 #[test]
66 fn test_get_expired() {
67 let mut cache = TtlCache::new(Duration::new(1, 0));
68 cache.insert("key1", "value1");
69
70 sleep(Duration::new(2, 0));
72
73 assert_eq!(cache.get(&"key1"), None);
74 }
75
76 #[test]
77 fn test_remove() {
78 let mut cache = TtlCache::new(Duration::new(5, 0));
79 cache.insert("key1", "value1");
80 cache.remove(&"key1");
81
82 assert_eq!(cache.get(&"key1"), None);
83 }
84
85 #[test]
86 fn test_cleanup() {
87 let mut cache = TtlCache::new(Duration::new(1, 0));
88 cache.insert("key1", "value1");
89 cache.insert("key2", "value2");
90
91 sleep(Duration::new(2, 0));
93
94 cache.cleanup();
95
96 assert_eq!(cache.get(&"key1"), None);
97 assert_eq!(cache.get(&"key2"), None);
98 }
99
100 #[test]
101 fn test_get_non_existent() {
102 let cache: TtlCache<&str, &str> = TtlCache::new(Duration::new(5, 0));
103 assert_eq!(cache.get(&"key1"), None);
104 }
105
106 #[test]
107 fn test_insert_and_get_multiple() {
108 let mut cache = TtlCache::new(Duration::new(5, 0));
109 cache.insert("key1", "value1");
110 cache.insert("key2", "value2");
111
112 assert_eq!(cache.get(&"key1"), Some("value1"));
113 assert_eq!(cache.get(&"key2"), Some("value2"));
114 }
115}