1mod cache_item;
2
3use std::marker::PhantomData;
4use std::collections::HashMap;
5
6use cache_item::CacheItem;
7
8pub struct Cache<T> {
9 cache_item_map: HashMap<String, CacheItem<T>>,
10 _mark: PhantomData<T>,
11}
12
13impl<T> Cache<T> {
14 pub fn new() -> Self {
15 Self {
16 cache_item_map: HashMap::new(),
17 _mark: PhantomData,
18 }
19 }
20 pub fn fetch(&mut self, key: &str, expires_in_secs: u64, calculation: impl Fn() -> T + 'static) -> &T {
21 if self.cache_item_map.get(key).is_none() {
22 let cache_item: CacheItem<T> = CacheItem::new(expires_in_secs, calculation);
23 self.cache_item_map.insert(key.to_string(), cache_item);
24 let in_cache_item = self.cache_item_map.get_mut(key).unwrap();
25 return in_cache_item.value()
26 } else {
27 let in_cache_item = self.cache_item_map.get_mut(key).unwrap();
28 if in_cache_item.is_value_expired() {
29 let cache_item: CacheItem<T> = CacheItem::new(expires_in_secs, calculation);
30 *in_cache_item = cache_item
31 }
32 return in_cache_item.value()
33 }
34 }
35 pub fn force_fetch(&mut self, key: &str, expires_in_secs: u64, calculation: impl Fn() -> T + 'static) -> &T {
36 let cache: CacheItem<T> = CacheItem::new(expires_in_secs, calculation);
37 self.cache_item_map.insert(key.to_string(), cache);
38 self.cache_item_map.get_mut(key).unwrap().value()
39 }
40 pub fn get(&mut self, key: &str) -> anyhow::Result<&T> {
41 match self.cache_item_map.get_mut(key) {
42 Some(cache_item) => {
43 Ok(cache_item.value())
44 },
45 None => Err(anyhow::anyhow!("cache not exists"))
46 }
47 }
48 pub fn insert(&mut self, key: &str, value: T) -> anyhow::Result<()> {
49 match self.cache_item_map.get_mut(key) {
50 Some(cache_item) => {
51 cache_item.update_value(value);
52 Ok(())
53 },
54 None => Err(anyhow::anyhow!("cache not exists"))
55 }
56 }
57 pub fn expire(&mut self, key: &str) -> anyhow::Result<()> {
58 match self.cache_item_map.get_mut(key) {
59 Some(cache_item) => {
60 cache_item.expire_value();
61 Ok(())
62 },
63 None => Err(anyhow::anyhow!("cache not exists"))
64 }
65 }
66 pub fn contains_key(&self, key: &str) -> bool {
67 self.cache_item_map.contains_key(key)
68 }
69 pub fn remove(&mut self, key: &str) -> Option<CacheItem<T>> {
70 self.cache_item_map.remove(key)
71 }
72 pub fn keys(&self) -> Vec<&String> {
73 self.cache_item_map.keys().collect()
74 }
75 pub fn clear_expired(&mut self) {
76 let keys = self.keys().iter().map(|i| i.to_string()).collect::<Vec<String>>();
77 for key in keys.iter() {
78 if let Some(cache_item) = self.cache_item_map.get_mut(key) {
79 if cache_item.is_value_expired() {
80 self.remove(key);
81 }
82 }
83 }
84 }
85 pub fn clear(&mut self) {
86 self.cache_item_map.clear();
87 }
88}
89
90
91#[cfg(test)]
92mod tests {
93 use super::*;
94 use std::{thread, time};
95
96 #[test]
97 fn test_fetch() {
98 let mut i32_cache = Cache::<i32>::new();
99 {
100 let a = 0;
101 let v1 = i32_cache.fetch("v1", 10, move || 1 + a);
102 assert_eq!(v1, &1);
103 }
104 {
105 let v2 = i32_cache.fetch("v2", 10, || 2);
106 assert_eq!(v2, &2);
107 }
108 {
110 let v1 = i32_cache.fetch("v1", 10, || 11);
111 assert_eq!(v1, &1);
112 }
113 {
114 let v2 = i32_cache.fetch("v2", 10, || 22);
115 assert_eq!(v2, &2);
116 }
117 {
119 let v1 = i32_cache.fetch("v1_expires", 3, || 1);
120 assert_eq!(v1, &1);
121 let v1 = i32_cache.fetch("v1_expires", 0, || 2);
122 assert_eq!(v1, &1); let three_secs = time::Duration::from_secs(3);
124 thread::sleep(three_secs);
125 let v1 = i32_cache.fetch("v1_expires", 0, || 3); assert_eq!(v1, &3);
127 let v1 = i32_cache.fetch("v1_expires", 0, || 4);
128 assert_eq!(v1, &4);
129 }
130 let mut string_cache = Cache::<String>::new();
131 {
132 let v1 = string_cache.fetch("v1", 10, || "1".to_string());
133 assert_eq!(v1, "1");
134 }
135 {
136 let v2 = string_cache.fetch("v2", 10, || "2".to_string());
137 assert_eq!(v2, "2");
138 }
139 {
141 let v1 = string_cache.fetch("v1", 10, || "11".to_string());
142 assert_eq!(v1, "1");
143 }
144 {
145 let v2 = string_cache.fetch("v2", 10, || "22".to_string());
146 assert_eq!(v2, "2");
147 }
148 }
149
150 #[test]
151 fn test_force_fetch() {
152 let mut i32_cache = Cache::<i32>::new();
153 let a = 0;
154 let v1 = i32_cache.force_fetch("v1", 10, move || 1 + a);
155 assert_eq!(v1, &1);
156 let v1 = i32_cache.fetch("v1", 10, move || 3 + a);
157 assert_eq!(v1, &1);
158 let v1 = i32_cache.force_fetch("v1", 10, move || 2 + a);
159 assert_eq!(v1, &2);
160 let v1 = i32_cache.fetch("v1", 10, move || 3 + a);
161 assert_eq!(v1, &2);
162 }
163
164 #[test]
165 fn test_get() {
166 let mut i32_cache = Cache::<i32>::new();
167 let a = 0;
168 let v1 = i32_cache.force_fetch("v1", 10, move || 1 + a);
169 assert_eq!(v1, &1);
170 let v1 = i32_cache.get("v1");
171 assert_eq!(v1.unwrap(), &1);
172 let v1 = i32_cache.get("v2");
173 assert!(v1.is_err());
174 }
175
176 #[test]
177 fn test_insert() {
178 let mut i32_cache = Cache::<i32>::new();
179 let a = 0;
180 let v1 = i32_cache.fetch("v1", 10, move || 1 + a);
181 assert_eq!(v1, &1);
182 i32_cache.insert("v1", 2).unwrap();
183 let v1 = i32_cache.fetch("v1", 10, move || 1 + a);
184 assert_eq!(v1, &2);
185 }
186
187 #[test]
188 fn test_expire() {
189 let mut i32_cache = Cache::<i32>::new();
190 let a = 0;
191 let v1 = i32_cache.fetch("v1", 10, move || 1 + a);
192 assert_eq!(v1, &1);
193 i32_cache.expire("v1").unwrap();
194 let v1 = i32_cache.fetch("v1", 10, move || 2 + a);
195 assert_eq!(v1, &2);
196 }
197
198 #[test]
199 fn test_remove() {
200 let mut i32_cache = Cache::<i32>::new();
201 let a = 0;
202 let v1 = i32_cache.force_fetch("v1", 10, move || 1 + a);
203 assert_eq!(v1, &1);
204 let v1 = i32_cache.remove("v1");
205 assert!(v1.is_some());
206 }
207
208 #[test]
209 fn test_others() {
210 let mut i32_cache = Cache::<i32>::new();
212 assert_eq!(i32_cache.contains_key("v1"), false);
213 i32_cache.force_fetch("v1", 10, move || 1);
214 i32_cache.force_fetch("v2", 0, move || 2);
215 assert_eq!(i32_cache.contains_key("v1"), true);
216 let mut keys = i32_cache.keys();
218 keys.sort();
219 assert_eq!(keys, vec!["v1", "v2"]);
220 i32_cache.clear_expired();
222 assert_eq!(i32_cache.keys(), vec!["v1"]);
223 i32_cache.clear();
225 assert!(i32_cache.keys().is_empty());
226 }
227}