1use std::collections::{HashMap, VecDeque};
11use std::sync::Mutex;
12
13pub trait ResponseCache: Send + Sync {
19 fn get(&self, key: &str) -> Option<String>;
21 fn put(&self, key: String, value: String);
23 fn clear(&self);
25}
26
27#[derive(Default)]
32pub struct MemoryCache {
33 inner: Mutex<CacheInner>,
34}
35
36struct CacheInner {
37 map: HashMap<String, String>,
38 order: VecDeque<String>,
39 max_entries: usize,
40}
41
42impl Default for CacheInner {
43 fn default() -> Self {
44 Self {
45 map: HashMap::new(),
46 order: VecDeque::new(),
47 max_entries: 256,
48 }
49 }
50}
51
52impl MemoryCache {
53 pub fn new() -> Self {
55 Self::default()
56 }
57
58 pub fn with_capacity(max_entries: usize) -> Self {
60 Self {
61 inner: Mutex::new(CacheInner {
62 max_entries: max_entries.max(1),
63 ..Default::default()
64 }),
65 }
66 }
67}
68
69impl ResponseCache for MemoryCache {
70 fn get(&self, key: &str) -> Option<String> {
71 self.inner
72 .lock()
73 .ok()
74 .and_then(|inner| inner.map.get(key).cloned())
75 }
76
77 fn put(&self, key: String, value: String) {
78 if let Ok(mut inner) = self.inner.lock() {
79 if inner.map.insert(key.clone(), value).is_none() {
80 inner.order.push_back(key);
81 }
82 while inner.order.len() > inner.max_entries {
83 if let Some(oldest) = inner.order.pop_front() {
84 inner.map.remove(&oldest);
85 }
86 }
87 }
88 }
89
90 fn clear(&self) {
91 if let Ok(mut inner) = self.inner.lock() {
92 inner.map.clear();
93 inner.order.clear();
94 }
95 }
96}
97
98#[cfg(test)]
99mod tests {
100 use super::*;
101
102 #[test]
103 fn test_cache_put_get() {
104 let cache = MemoryCache::new();
105 assert!(cache.get("k").is_none());
106 cache.put("k".to_string(), "v".to_string());
107 assert_eq!(cache.get("k").as_deref(), Some("v"));
108 }
109
110 #[test]
111 fn test_cache_evicts_oldest() {
112 let cache = MemoryCache::with_capacity(2);
113 cache.put("a".to_string(), "1".to_string());
114 cache.put("b".to_string(), "2".to_string());
115 cache.put("c".to_string(), "3".to_string());
116 assert!(cache.get("a").is_none(), "最旧条目应被淘汰");
117 assert_eq!(cache.get("b").as_deref(), Some("2"));
118 assert_eq!(cache.get("c").as_deref(), Some("3"));
119 }
120
121 #[test]
122 fn test_cache_clear() {
123 let cache = MemoryCache::new();
124 cache.put("a".to_string(), "1".to_string());
125 cache.clear();
126 assert!(cache.get("a").is_none());
127 }
128}