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.retain(|_, entry| {
62 now.duration_since(entry.inserted_at) < self.ttl
63 });
64 }
65
66 pub fn invalidate(&mut self, key: &K) {
68 self.entries.remove(key);
69 }
70}
71
72#[cfg(test)]
73mod tests {
74 use super::*;
75 use std::thread;
76
77 #[test]
78 fn test_cache_basic() {
79 let mut cache = Cache::new(Duration::from_secs(60));
80
81 cache.insert("key1", "value1");
82 assert_eq!(cache.get(&"key1"), Some("value1"));
83 assert_eq!(cache.get(&"key2"), None);
84 }
85
86 #[test]
87 fn test_cache_expiration() {
88 let mut cache = Cache::new(Duration::from_millis(50));
89
90 cache.insert("key1", "value1");
91 assert_eq!(cache.get(&"key1"), Some("value1"));
92
93 thread::sleep(Duration::from_millis(60));
94 assert_eq!(cache.get(&"key1"), None);
95 }
96
97 #[test]
98 fn test_cache_cleanup() {
99 let mut cache = Cache::new(Duration::from_millis(50));
100
101 cache.insert("key1", "value1");
102 cache.insert("key2", "value2");
103
104 thread::sleep(Duration::from_millis(60));
105
106 cache.insert("key3", "value3");
107 cache.cleanup();
108
109 assert_eq!(cache.entries.len(), 1);
110 assert_eq!(cache.get(&"key3"), Some("value3"));
111 }
112}