1#![warn(missing_docs)]
9
10use serde::{Serialize, de::DeserializeOwned};
11use std::{fmt, time::Duration};
12
13#[derive(Debug)]
15pub enum CacheError {
16 ConnectionFailed(String),
18
19 SerializationFailed(String),
21
22 DeserializationFailed(String),
24
25 KeyNotFound(String),
27
28 Timeout(String),
30
31 Internal(String),
33}
34
35impl fmt::Display for CacheError {
36 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
37 match self {
38 CacheError::ConnectionFailed(msg) => write!(f, "Cache connection failed: {}", msg),
39 CacheError::SerializationFailed(msg) => write!(f, "Serialization failed: {}", msg),
40 CacheError::DeserializationFailed(msg) => write!(f, "Deserialization failed: {}", msg),
41 CacheError::KeyNotFound(msg) => write!(f, "Key not found: {}", msg),
42 CacheError::Timeout(msg) => write!(f, "Operation timeout: {}", msg),
43 CacheError::Internal(msg) => write!(f, "Cache internal error: {}", msg),
44 }
45 }
46}
47
48impl std::error::Error for CacheError {}
49
50pub type CacheResult<T> = Result<T, CacheError>;
52
53#[derive(Debug, Clone)]
55pub struct CacheConfig {
56 pub key_prefix: String,
58 pub default_ttl: Option<Duration>,
60 pub connection_timeout: Duration,
62 pub operation_timeout: Duration,
64}
65
66impl Default for CacheConfig {
67 fn default() -> Self {
68 Self {
69 key_prefix: String::new(),
70 default_ttl: Some(Duration::from_secs(3600)),
71 connection_timeout: Duration::from_secs(5),
72 operation_timeout: Duration::from_secs(3),
73 }
74 }
75}
76
77#[async_trait::async_trait]
82pub trait CacheBackend: Send + Sync {
83 async fn get_bytes(&self, key: &str) -> CacheResult<Option<Vec<u8>>>;
85
86 async fn set_bytes(&self, key: &str, value: &[u8], ttl: Option<Duration>) -> CacheResult<()>;
88
89 async fn delete(&self, key: &str) -> CacheResult<bool>;
91
92 async fn exists(&self, key: &str) -> CacheResult<bool>;
94
95 async fn expire(&self, key: &str, ttl: Duration) -> CacheResult<bool>;
97
98 async fn ttl(&self, key: &str) -> CacheResult<Option<Duration>>;
100
101 async fn mget_bytes(&self, keys: &[&str]) -> CacheResult<Vec<Option<Vec<u8>>>>;
103
104 async fn mset_bytes(&self, items: &[(&str, &[u8])], ttl: Option<Duration>) -> CacheResult<()>;
106
107 async fn mdelete(&self, keys: &[&str]) -> CacheResult<u64>;
109
110 async fn incr(&self, key: &str, delta: i64) -> CacheResult<i64>;
112
113 async fn decr(&self, key: &str, delta: i64) -> CacheResult<i64>;
115
116 async fn clear(&self) -> CacheResult<()>;
118
119 fn config(&self) -> &CacheConfig;
121}
122
123pub struct CacheService {
125 backend: Box<dyn CacheBackend>,
126}
127
128impl CacheService {
129 pub fn new(backend: Box<dyn CacheBackend>) -> Self {
131 Self { backend }
132 }
133
134 pub async fn get<T: DeserializeOwned>(&self, key: &str) -> CacheResult<Option<T>> {
136 let bytes = self.backend.get_bytes(key).await?;
137 match bytes {
138 Some(data) => {
139 let value = serde_json::from_slice(&data).map_err(|e| CacheError::DeserializationFailed(e.to_string()))?;
140 Ok(Some(value))
141 }
142 None => Ok(None),
143 }
144 }
145
146 pub async fn set<T: Serialize + ?Sized>(&self, key: &str, value: &T, ttl: Option<Duration>) -> CacheResult<()> {
148 let data = serde_json::to_vec(value).map_err(|e| CacheError::SerializationFailed(e.to_string()))?;
149 self.backend.set_bytes(key, &data, ttl).await
150 }
151
152 pub async fn delete(&self, key: &str) -> CacheResult<bool> {
154 self.backend.delete(key).await
155 }
156
157 pub async fn exists(&self, key: &str) -> CacheResult<bool> {
159 self.backend.exists(key).await
160 }
161
162 pub async fn expire(&self, key: &str, ttl: Duration) -> CacheResult<bool> {
164 self.backend.expire(key, ttl).await
165 }
166
167 pub async fn ttl(&self, key: &str) -> CacheResult<Option<Duration>> {
169 self.backend.ttl(key).await
170 }
171
172 pub async fn mget<T: DeserializeOwned>(&self, keys: &[&str]) -> CacheResult<Vec<Option<T>>> {
174 let bytes_list = self.backend.mget_bytes(keys).await?;
175 let mut results = Vec::with_capacity(bytes_list.len());
176 for bytes in bytes_list {
177 match bytes {
178 Some(data) => {
179 let value = serde_json::from_slice(&data).map_err(|e| CacheError::DeserializationFailed(e.to_string()))?;
180 results.push(Some(value));
181 }
182 None => results.push(None),
183 }
184 }
185 Ok(results)
186 }
187
188 pub async fn mset<T: Serialize + ?Sized>(&self, items: &[(&str, &T)], ttl: Option<Duration>) -> CacheResult<()> {
190 let byte_items: Vec<(&str, Vec<u8>)> = items
191 .iter()
192 .map(|(k, v)| {
193 let data = serde_json::to_vec(v).map_err(|e| CacheError::SerializationFailed(e.to_string()))?;
194 Ok((*k, data))
195 })
196 .collect::<CacheResult<_>>()?;
197
198 let refs: Vec<(&str, &[u8])> = byte_items.iter().map(|(k, v)| (*k, v.as_slice())).collect();
199 self.backend.mset_bytes(&refs, ttl).await
200 }
201
202 pub async fn mdelete(&self, keys: &[&str]) -> CacheResult<u64> {
204 self.backend.mdelete(keys).await
205 }
206
207 pub async fn incr(&self, key: &str, delta: i64) -> CacheResult<i64> {
209 self.backend.incr(key, delta).await
210 }
211
212 pub async fn decr(&self, key: &str, delta: i64) -> CacheResult<i64> {
214 self.backend.decr(key, delta).await
215 }
216
217 pub async fn clear(&self) -> CacheResult<()> {
219 self.backend.clear().await
220 }
221
222 pub fn config(&self) -> &CacheConfig {
224 self.backend.config()
225 }
226
227 pub fn build_key(&self, key: &str) -> String {
229 let config = self.config();
230 if config.key_prefix.is_empty() { key.to_string() } else { format!("{}:{}", config.key_prefix, key) }
231 }
232}
233
234pub mod memory {
236 use super::*;
237 use std::{collections::HashMap, sync::Arc};
238 use tokio::{sync::RwLock, time::Instant};
239
240 struct CacheEntry {
242 data: Vec<u8>,
243 expires_at: Option<Instant>,
244 }
245
246 impl CacheEntry {
247 fn is_expired(&self) -> bool {
248 self.expires_at.map(|exp| Instant::now() >= exp).unwrap_or(false)
249 }
250 }
251
252 pub struct MemoryCacheBackend {
254 config: CacheConfig,
255 store: Arc<RwLock<HashMap<String, CacheEntry>>>,
256 }
257
258 impl MemoryCacheBackend {
259 pub fn new(config: CacheConfig) -> Self {
261 Self { config, store: Arc::new(RwLock::new(HashMap::new())) }
262 }
263
264 fn build_key(&self, key: &str) -> String {
265 if self.config.key_prefix.is_empty() { key.to_string() } else { format!("{}:{}", self.config.key_prefix, key) }
266 }
267 }
268
269 #[async_trait::async_trait]
270 impl CacheBackend for MemoryCacheBackend {
271 async fn get_bytes(&self, key: &str) -> CacheResult<Option<Vec<u8>>> {
272 let full_key = self.build_key(key);
273 let store = self.store.read().await;
274
275 if let Some(entry) = store.get(&full_key) {
276 if entry.is_expired() {
277 return Ok(None);
278 }
279 return Ok(Some(entry.data.clone()));
280 }
281 Ok(None)
282 }
283
284 async fn set_bytes(&self, key: &str, value: &[u8], ttl: Option<Duration>) -> CacheResult<()> {
285 let full_key = self.build_key(key);
286 let effective_ttl = ttl.or(self.config.default_ttl);
287 let expires_at = effective_ttl.map(|d| Instant::now() + d);
288
289 let entry = CacheEntry { data: value.to_vec(), expires_at };
290 let mut store = self.store.write().await;
291 store.insert(full_key, entry);
292 Ok(())
293 }
294
295 async fn delete(&self, key: &str) -> CacheResult<bool> {
296 let full_key = self.build_key(key);
297 let mut store = self.store.write().await;
298 Ok(store.remove(&full_key).is_some())
299 }
300
301 async fn exists(&self, key: &str) -> CacheResult<bool> {
302 let full_key = self.build_key(key);
303 let store = self.store.read().await;
304 if let Some(entry) = store.get(&full_key) {
305 return Ok(!entry.is_expired());
306 }
307 Ok(false)
308 }
309
310 async fn expire(&self, key: &str, ttl: Duration) -> CacheResult<bool> {
311 let full_key = self.build_key(key);
312 let mut store = self.store.write().await;
313 if let Some(entry) = store.get_mut(&full_key) {
314 if entry.is_expired() {
315 return Ok(false);
316 }
317 entry.expires_at = Some(Instant::now() + ttl);
318 return Ok(true);
319 }
320 Ok(false)
321 }
322
323 async fn ttl(&self, key: &str) -> CacheResult<Option<Duration>> {
324 let full_key = self.build_key(key);
325 let store = self.store.read().await;
326 if let Some(entry) = store.get(&full_key) {
327 if entry.is_expired() {
328 return Ok(None);
329 }
330 if let Some(expires_at) = entry.expires_at {
331 let now = Instant::now();
332 if expires_at > now {
333 return Ok(Some(expires_at - now));
334 }
335 }
336 }
337 Ok(None)
338 }
339
340 async fn mget_bytes(&self, keys: &[&str]) -> CacheResult<Vec<Option<Vec<u8>>>> {
341 let mut results = Vec::with_capacity(keys.len());
342 for key in keys {
343 results.push(self.get_bytes(key).await?);
344 }
345 Ok(results)
346 }
347
348 async fn mset_bytes(&self, items: &[(&str, &[u8])], ttl: Option<Duration>) -> CacheResult<()> {
349 for (key, value) in items {
350 self.set_bytes(key, value, ttl).await?;
351 }
352 Ok(())
353 }
354
355 async fn mdelete(&self, keys: &[&str]) -> CacheResult<u64> {
356 let mut count = 0u64;
357 for key in keys {
358 if self.delete(key).await? {
359 count += 1;
360 }
361 }
362 Ok(count)
363 }
364
365 async fn incr(&self, key: &str, delta: i64) -> CacheResult<i64> {
366 let full_key = self.build_key(key);
367 let mut store = self.store.write().await;
368
369 let entry = store.entry(full_key.clone()).or_insert(CacheEntry { data: b"0".to_vec(), expires_at: None });
370
371 let mut value: i64 = String::from_utf8_lossy(&entry.data).parse().unwrap_or(0);
372 value += delta;
373 entry.data = value.to_string().into_bytes();
374 Ok(value)
375 }
376
377 async fn decr(&self, key: &str, delta: i64) -> CacheResult<i64> {
378 self.incr(key, -delta).await
379 }
380
381 async fn clear(&self) -> CacheResult<()> {
382 let mut store = self.store.write().await;
383 if self.config.key_prefix.is_empty() {
384 store.clear();
385 }
386 else {
387 let prefix = format!("{}:", self.config.key_prefix);
388 store.retain(|k, _| !k.starts_with(&prefix));
389 }
390 Ok(())
391 }
392
393 fn config(&self) -> &CacheConfig {
394 &self.config
395 }
396 }
397}
398
399pub fn memory_cache(config: CacheConfig) -> CacheService {
401 CacheService::new(Box::new(memory::MemoryCacheBackend::new(config)))
402}