Skip to main content

ai_lib_rust/cache/
backend.rs

1//! Cache backend implementations.
2
3use async_trait::async_trait;
4use std::collections::HashMap;
5use std::sync::{Arc, RwLock};
6use std::time::{Duration, Instant};
7use super::key::CacheKey;
8use crate::Result;
9
10#[derive(Clone)]
11struct CacheEntry { data: Vec<u8>, created_at: Instant, ttl: Duration, last_accessed: Instant }
12
13impl CacheEntry {
14    fn new(data: Vec<u8>, ttl: Duration) -> Self { let now = Instant::now(); Self { data, created_at: now, ttl, last_accessed: now } }
15    fn is_expired(&self) -> bool { self.created_at.elapsed() > self.ttl }
16}
17
18#[async_trait]
19pub trait CacheBackend: Send + Sync {
20    async fn get(&self, key: &CacheKey) -> Result<Option<Vec<u8>>>;
21    async fn set(&self, key: &CacheKey, value: &[u8], ttl: Duration) -> Result<()>;
22    async fn delete(&self, key: &CacheKey) -> Result<bool>;
23    async fn exists(&self, key: &CacheKey) -> Result<bool>;
24    async fn clear(&self) -> Result<()>;
25    async fn len(&self) -> Result<usize>;
26    fn name(&self) -> &'static str;
27}
28
29pub struct MemoryCache { entries: Arc<RwLock<HashMap<String, CacheEntry>>>, max_entries: usize }
30
31impl MemoryCache {
32    pub fn new(max_entries: usize) -> Self { Self { entries: Arc::new(RwLock::new(HashMap::new())), max_entries } }
33    fn evict_if_needed(&self, entries: &mut HashMap<String, CacheEntry>) {
34        entries.retain(|_, e| !e.is_expired());
35        while entries.len() >= self.max_entries {
36            let oldest = entries.iter().min_by_key(|(_, e)| e.last_accessed).map(|(k, _)| k.clone());
37            if let Some(k) = oldest { entries.remove(&k); } else { break; }
38        }
39    }
40}
41
42#[async_trait]
43impl CacheBackend for MemoryCache {
44    async fn get(&self, key: &CacheKey) -> Result<Option<Vec<u8>>> {
45        let mut entries = self.entries.write().unwrap();
46        if let Some(entry) = entries.get_mut(&key.hash) {
47            if entry.is_expired() { entries.remove(&key.hash); return Ok(None); }
48            entry.last_accessed = Instant::now();
49            return Ok(Some(entry.data.clone()));
50        }
51        Ok(None)
52    }
53    async fn set(&self, key: &CacheKey, value: &[u8], ttl: Duration) -> Result<()> {
54        let mut entries = self.entries.write().unwrap();
55        self.evict_if_needed(&mut entries);
56        entries.insert(key.hash.clone(), CacheEntry::new(value.to_vec(), ttl));
57        Ok(())
58    }
59    async fn delete(&self, key: &CacheKey) -> Result<bool> { Ok(self.entries.write().unwrap().remove(&key.hash).is_some()) }
60    async fn exists(&self, key: &CacheKey) -> Result<bool> {
61        let entries = self.entries.read().unwrap();
62        Ok(entries.get(&key.hash).map(|e| !e.is_expired()).unwrap_or(false))
63    }
64    async fn clear(&self) -> Result<()> { self.entries.write().unwrap().clear(); Ok(()) }
65    async fn len(&self) -> Result<usize> { Ok(self.entries.read().unwrap().values().filter(|e| !e.is_expired()).count()) }
66    fn name(&self) -> &'static str { "memory" }
67}
68
69pub struct NullCache;
70impl NullCache { pub fn new() -> Self { Self } }
71impl Default for NullCache { fn default() -> Self { Self::new() } }
72
73#[async_trait]
74impl CacheBackend for NullCache {
75    async fn get(&self, _: &CacheKey) -> Result<Option<Vec<u8>>> { Ok(None) }
76    async fn set(&self, _: &CacheKey, _: &[u8], _: Duration) -> Result<()> { Ok(()) }
77    async fn delete(&self, _: &CacheKey) -> Result<bool> { Ok(false) }
78    async fn exists(&self, _: &CacheKey) -> Result<bool> { Ok(false) }
79    async fn clear(&self) -> Result<()> { Ok(()) }
80    async fn len(&self) -> Result<usize> { Ok(0) }
81    fn name(&self) -> &'static str { "null" }
82}