ferrous_forge/rust_version/
cache.rs1use std::collections::HashMap;
4use std::time::{Duration, Instant};
5
6struct CacheEntry<V> {
8 value: V,
9 inserted_at: Instant,
10}
11
12pub struct Cache<K, V> {
14 entries: HashMap<K, CacheEntry<V>>,
15 ttl: Duration,
16}
17
18impl<K, V> Cache<K, V>
19where
20 K: Eq + std::hash::Hash,
21 V: Clone,
22{
23 pub fn new(ttl: Duration) -> Self {
25 Self {
26 entries: HashMap::new(),
27 ttl,
28 }
29 }
30
31 pub fn get(&self, key: &K) -> Option<V> {
33 self.entries.get(key).and_then(|entry| {
34 if entry.inserted_at.elapsed() < self.ttl {
35 Some(entry.value.clone())
36 } else {
37 None
38 }
39 })
40 }
41
42 pub fn insert(&mut self, key: K, value: V) {
44 self.entries.insert(
45 key,
46 CacheEntry {
47 value,
48 inserted_at: Instant::now(),
49 },
50 );
51 }
52
53 pub fn clear(&mut self) {
55 self.entries.clear();
56 }
57
58 pub fn cleanup(&mut self) {
60 let now = Instant::now();
61 self.entries
62 .retain(|_, entry| now.duration_since(entry.inserted_at) < self.ttl);
63 }
64
65 pub fn invalidate(&mut self, key: &K) {
67 self.entries.remove(key);
68 }
69}
70
71#[cfg(test)]
72mod tests {
73 use super::*;
74 use std::thread;
75
76 #[test]
77 fn test_cache_basic() {
78 let mut cache = Cache::new(Duration::from_secs(60));
79
80 cache.insert("key1", "value1");
81 assert_eq!(cache.get(&"key1"), Some("value1"));
82 assert_eq!(cache.get(&"key2"), None);
83 }
84
85 #[test]
86 fn test_cache_expiration() {
87 let mut cache = Cache::new(Duration::from_millis(50));
88
89 cache.insert("key1", "value1");
90 assert_eq!(cache.get(&"key1"), Some("value1"));
91
92 thread::sleep(Duration::from_millis(60));
93 assert_eq!(cache.get(&"key1"), None);
94 }
95
96 #[test]
97 fn test_cache_cleanup() {
98 let mut cache = Cache::new(Duration::from_millis(50));
99
100 cache.insert("key1", "value1");
101 cache.insert("key2", "value2");
102
103 thread::sleep(Duration::from_millis(60));
104
105 cache.insert("key3", "value3");
106 cache.cleanup();
107
108 assert_eq!(cache.entries.len(), 1);
109 assert_eq!(cache.get(&"key3"), Some("value3"));
110 }
111}