Skip to main content

wae_cache/
lib.rs

1//! WAE Cache - 缓存服务抽象层
2//!
3//! 提供统一的缓存能力抽象,支持多种缓存后端。
4//!
5//! 深度融合 tokio 运行时,所有 API 都是异步优先设计。
6//! 微服务架构友好,支持分布式缓存、过期策略等特性。
7
8#![warn(missing_docs)]
9
10use serde::{Serialize, de::DeserializeOwned};
11use std::time::Duration;
12use wae_types::WaeError;
13
14/// 缓存操作结果类型
15pub type CacheResult<T> = Result<T, WaeError>;
16
17/// 缓存驱逐策略
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
19pub enum EvictionPolicy {
20    /// 无驱逐策略,无边界缓存(FIFO 行为)
21    None,
22    /// 最近最少使用驱逐策略
23    Lru,
24    /// 最不常用驱逐策略
25    Lfu,
26}
27
28impl Default for EvictionPolicy {
29    fn default() -> Self {
30        Self::None
31    }
32}
33
34/// 缓存配置
35#[derive(Debug, Clone)]
36pub struct CacheConfig {
37    /// 缓存键前缀
38    pub key_prefix: String,
39    /// 默认过期时间
40    pub default_ttl: Option<Duration>,
41    /// 连接超时
42    pub connection_timeout: Duration,
43    /// 操作超时
44    pub operation_timeout: Duration,
45    /// 最大容量(可选,None 表示无限制)
46    pub max_capacity: Option<usize>,
47    /// 驱逐策略
48    pub eviction_policy: EvictionPolicy,
49}
50
51impl Default for CacheConfig {
52    fn default() -> Self {
53        Self {
54            key_prefix: String::new(),
55            default_ttl: Some(Duration::from_secs(3600)),
56            connection_timeout: Duration::from_secs(5),
57            operation_timeout: Duration::from_secs(3),
58            max_capacity: None,
59            eviction_policy: EvictionPolicy::default(),
60        }
61    }
62}
63
64/// 缓存服务核心 trait (dyn 兼容)
65///
66/// 定义统一的缓存操作接口,使用原始字节进行存储。
67/// 所有方法都是异步的,适配 tokio 运行时。
68#[async_trait::async_trait]
69pub trait CacheBackend: Send + Sync {
70    /// 获取缓存原始字节
71    async fn get_bytes(&self, key: &str) -> CacheResult<Option<Vec<u8>>>;
72
73    /// 设置缓存原始字节
74    async fn set_bytes(&self, key: &str, value: &[u8], ttl: Option<Duration>) -> CacheResult<()>;
75
76    /// 删除缓存键
77    async fn delete(&self, key: &str) -> CacheResult<bool>;
78
79    /// 检查键是否存在
80    async fn exists(&self, key: &str) -> CacheResult<bool>;
81
82    /// 设置键的过期时间
83    async fn expire(&self, key: &str, ttl: Duration) -> CacheResult<bool>;
84
85    /// 获取键的剩余过期时间
86    async fn ttl(&self, key: &str) -> CacheResult<Option<Duration>>;
87
88    /// 批量获取缓存原始字节
89    async fn mget_bytes(&self, keys: &[&str]) -> CacheResult<Vec<Option<Vec<u8>>>>;
90
91    /// 批量设置缓存原始字节
92    async fn mset_bytes(&self, items: &[(&str, &[u8])], ttl: Option<Duration>) -> CacheResult<()>;
93
94    /// 批量删除缓存键
95    async fn mdelete(&self, keys: &[&str]) -> CacheResult<u64>;
96
97    /// 自增操作
98    async fn incr(&self, key: &str, delta: i64) -> CacheResult<i64>;
99
100    /// 自减操作
101    async fn decr(&self, key: &str, delta: i64) -> CacheResult<i64>;
102
103    /// 清空当前命名空间下的所有缓存
104    async fn clear(&self) -> CacheResult<()>;
105
106    /// 获取缓存配置
107    fn config(&self) -> &CacheConfig;
108}
109
110/// 缓存服务 (提供泛型封装)
111pub struct CacheService {
112    backend: Box<dyn CacheBackend>,
113}
114
115impl CacheService {
116    /// 从后端创建缓存服务
117    pub fn new(backend: Box<dyn CacheBackend>) -> Self {
118        Self { backend }
119    }
120
121    /// 获取缓存值
122    pub async fn get<T: DeserializeOwned>(&self, key: &str) -> CacheResult<Option<T>> {
123        let bytes = self.backend.get_bytes(key).await?;
124        match bytes {
125            Some(data) => {
126                let value =
127                    serde_json::from_slice(&data).map_err(|_| WaeError::deserialization_failed(std::any::type_name::<T>()))?;
128                Ok(Some(value))
129            }
130            None => Ok(None),
131        }
132    }
133
134    /// 设置缓存值
135    pub async fn set<T: Serialize + ?Sized>(&self, key: &str, value: &T, ttl: Option<Duration>) -> CacheResult<()> {
136        let data = serde_json::to_vec(value).map_err(|_| WaeError::serialization_failed(std::any::type_name::<T>()))?;
137        self.backend.set_bytes(key, &data, ttl).await
138    }
139
140    /// 删除缓存键
141    pub async fn delete(&self, key: &str) -> CacheResult<bool> {
142        self.backend.delete(key).await
143    }
144
145    /// 检查键是否存在
146    pub async fn exists(&self, key: &str) -> CacheResult<bool> {
147        self.backend.exists(key).await
148    }
149
150    /// 设置键的过期时间
151    pub async fn expire(&self, key: &str, ttl: Duration) -> CacheResult<bool> {
152        self.backend.expire(key, ttl).await
153    }
154
155    /// 获取键的剩余过期时间
156    pub async fn ttl(&self, key: &str) -> CacheResult<Option<Duration>> {
157        self.backend.ttl(key).await
158    }
159
160    /// 批量获取缓存值
161    pub async fn mget<T: DeserializeOwned>(&self, keys: &[&str]) -> CacheResult<Vec<Option<T>>> {
162        let bytes_list = self.backend.mget_bytes(keys).await?;
163        let mut results = Vec::with_capacity(bytes_list.len());
164        for bytes in bytes_list {
165            match bytes {
166                Some(data) => {
167                    let value = serde_json::from_slice(&data)
168                        .map_err(|_| WaeError::deserialization_failed(std::any::type_name::<T>()))?;
169                    results.push(Some(value));
170                }
171                None => results.push(None),
172            }
173        }
174        Ok(results)
175    }
176
177    /// 批量设置缓存值
178    pub async fn mset<T: Serialize + ?Sized>(&self, items: &[(&str, &T)], ttl: Option<Duration>) -> CacheResult<()> {
179        let byte_items: Vec<(&str, Vec<u8>)> = items
180            .iter()
181            .map(|(k, v)| {
182                let data = serde_json::to_vec(v).map_err(|_| WaeError::serialization_failed(std::any::type_name::<T>()))?;
183                Ok((*k, data))
184            })
185            .collect::<CacheResult<_>>()?;
186
187        let refs: Vec<(&str, &[u8])> = byte_items.iter().map(|(k, v)| (*k, v.as_slice())).collect();
188        self.backend.mset_bytes(&refs, ttl).await
189    }
190
191    /// 批量删除缓存键
192    pub async fn mdelete(&self, keys: &[&str]) -> CacheResult<u64> {
193        self.backend.mdelete(keys).await
194    }
195
196    /// 自增操作
197    pub async fn incr(&self, key: &str, delta: i64) -> CacheResult<i64> {
198        self.backend.incr(key, delta).await
199    }
200
201    /// 自减操作
202    pub async fn decr(&self, key: &str, delta: i64) -> CacheResult<i64> {
203        self.backend.decr(key, delta).await
204    }
205
206    /// 清空缓存
207    pub async fn clear(&self) -> CacheResult<()> {
208        self.backend.clear().await
209    }
210
211    /// 获取配置
212    pub fn config(&self) -> &CacheConfig {
213        self.backend.config()
214    }
215
216    /// 构建带前缀的完整键
217    pub fn build_key(&self, key: &str) -> String {
218        let config = self.config();
219        if config.key_prefix.is_empty() { key.to_string() } else { format!("{}:{}", config.key_prefix, key) }
220    }
221}
222
223/// Redis 缓存实现
224#[cfg(feature = "redis")]
225pub mod redis;
226
227/// 内存缓存实现
228pub mod memory {
229    use super::*;
230    use std::{collections::HashMap, sync::Arc};
231    use tokio::{sync::RwLock, time::Instant};
232
233    /// 缓存条目
234    #[derive(Debug, Clone)]
235    struct CacheEntry {
236        data: Vec<u8>,
237        expires_at: Option<Instant>,
238    }
239
240    impl CacheEntry {
241        fn is_expired(&self) -> bool {
242            self.expires_at.map(|exp| Instant::now() >= exp).unwrap_or(false)
243        }
244    }
245
246    /// 无边界缓存存储(无驱逐策略)
247    struct UnboundedStore {
248        map: HashMap<String, CacheEntry>,
249    }
250
251    impl UnboundedStore {
252        fn new() -> Self {
253            Self { map: HashMap::new() }
254        }
255    }
256
257    /// LRU 缓存存储
258    struct LruStore {
259        map: HashMap<String, CacheEntry>,
260        order: Vec<String>,
261        max_capacity: Option<usize>,
262    }
263
264    impl LruStore {
265        fn new(max_capacity: Option<usize>) -> Self {
266            Self { map: HashMap::new(), order: Vec::new(), max_capacity }
267        }
268
269        fn touch(&mut self, key: &str) {
270            if let Some(pos) = self.order.iter().position(|k| k == key) {
271                self.order.remove(pos);
272                self.order.push(key.to_string());
273            }
274        }
275
276        fn evict_if_needed(&mut self) {
277            if let Some(max_cap) = self.max_capacity {
278                while self.map.len() > max_cap {
279                    if let Some(key) = self.order.first().cloned() {
280                        self.map.remove(&key);
281                        self.order.remove(0);
282                    }
283                    else {
284                        break;
285                    }
286                }
287            }
288        }
289    }
290
291    /// LFU 缓存存储
292    struct LfuStore {
293        map: HashMap<String, CacheEntry>,
294        frequencies: HashMap<String, u64>,
295        max_capacity: Option<usize>,
296    }
297
298    impl LfuStore {
299        fn new(max_capacity: Option<usize>) -> Self {
300            Self { map: HashMap::new(), frequencies: HashMap::new(), max_capacity }
301        }
302
303        fn increment_frequency(&mut self, key: &str) {
304            *self.frequencies.entry(key.to_string()).or_insert(0) += 1;
305        }
306
307        fn evict_if_needed(&mut self) {
308            if let Some(max_cap) = self.max_capacity {
309                while self.map.len() > max_cap {
310                    if let Some(key_to_evict) = self.find_least_frequent_key() {
311                        self.map.remove(&key_to_evict);
312                        self.frequencies.remove(&key_to_evict);
313                    }
314                    else {
315                        break;
316                    }
317                }
318            }
319        }
320
321        fn find_least_frequent_key(&self) -> Option<String> {
322            let mut min_freq = u64::MAX;
323            let mut min_key = None;
324            for (key, &freq) in &self.frequencies {
325                if freq < min_freq {
326                    min_freq = freq;
327                    min_key = Some(key.clone());
328                }
329            }
330            min_key
331        }
332    }
333
334    /// 缓存存储枚举,支持多种驱逐策略
335    enum CacheStore {
336        /// 无边界存储
337        Unbounded(UnboundedStore),
338        /// LRU 存储
339        Lru(LruStore),
340        /// LFU 存储
341        Lfu(LfuStore),
342    }
343
344    impl CacheStore {
345        fn get(&mut self, key: &str) -> Option<CacheEntry> {
346            match self {
347                CacheStore::Unbounded(store) => store.map.get(key).cloned(),
348                CacheStore::Lru(store) => {
349                    let has_key = store.map.contains_key(key);
350                    if has_key {
351                        store.touch(key);
352                        store.map.get(key).cloned()
353                    }
354                    else {
355                        None
356                    }
357                }
358                CacheStore::Lfu(store) => {
359                    let has_key = store.map.contains_key(key);
360                    if has_key {
361                        store.increment_frequency(key);
362                        store.map.get(key).cloned()
363                    }
364                    else {
365                        None
366                    }
367                }
368            }
369        }
370
371        fn insert(&mut self, key: String, entry: CacheEntry) {
372            match self {
373                CacheStore::Unbounded(store) => {
374                    store.map.insert(key, entry);
375                }
376                CacheStore::Lru(store) => {
377                    if store.map.contains_key(&key) {
378                        store.touch(&key);
379                    }
380                    else {
381                        store.order.push(key.clone());
382                    }
383                    store.map.insert(key, entry);
384                    store.evict_if_needed();
385                }
386                CacheStore::Lfu(store) => {
387                    if store.map.contains_key(&key) {
388                        store.increment_frequency(&key);
389                    }
390                    else {
391                        *store.frequencies.entry(key.clone()).or_insert(0) = 1;
392                    }
393                    store.map.insert(key, entry);
394                    store.evict_if_needed();
395                }
396            }
397        }
398
399        fn remove(&mut self, key: &str) -> Option<CacheEntry> {
400            match self {
401                CacheStore::Unbounded(store) => store.map.remove(key),
402                CacheStore::Lru(store) => {
403                    if let Some(entry) = store.map.remove(key) {
404                        if let Some(pos) = store.order.iter().position(|k| k == key) {
405                            store.order.remove(pos);
406                        }
407                        Some(entry)
408                    }
409                    else {
410                        None
411                    }
412                }
413                CacheStore::Lfu(store) => {
414                    if let Some(entry) = store.map.remove(key) {
415                        store.frequencies.remove(key);
416                        Some(entry)
417                    }
418                    else {
419                        None
420                    }
421                }
422            }
423        }
424
425        fn contains_key(&self, key: &str) -> bool {
426            match self {
427                CacheStore::Unbounded(store) => store.map.contains_key(key),
428                CacheStore::Lru(store) => store.map.contains_key(key),
429                CacheStore::Lfu(store) => store.map.contains_key(key),
430            }
431        }
432
433        fn get_mut(&mut self, key: &str) -> Option<&mut CacheEntry> {
434            match self {
435                CacheStore::Unbounded(store) => store.map.get_mut(key),
436                CacheStore::Lru(store) => {
437                    if store.map.contains_key(key) {
438                        store.touch(key);
439                        store.map.get_mut(key)
440                    }
441                    else {
442                        None
443                    }
444                }
445                CacheStore::Lfu(store) => {
446                    if store.map.contains_key(key) {
447                        store.increment_frequency(key);
448                        store.map.get_mut(key)
449                    }
450                    else {
451                        None
452                    }
453                }
454            }
455        }
456
457        fn clear(&mut self) {
458            match self {
459                CacheStore::Unbounded(store) => store.map.clear(),
460                CacheStore::Lru(store) => {
461                    store.map.clear();
462                    store.order.clear();
463                }
464                CacheStore::Lfu(store) => {
465                    store.map.clear();
466                    store.frequencies.clear();
467                }
468            }
469        }
470
471        fn retain<F>(&mut self, mut f: F)
472        where
473            F: FnMut(&String, &mut CacheEntry) -> bool,
474        {
475            match self {
476                CacheStore::Unbounded(store) => store.map.retain(|k, v| f(k, v)),
477                CacheStore::Lru(store) => {
478                    let mut keys_to_remove = Vec::new();
479                    for (key, entry) in &mut store.map {
480                        if !f(key, entry) {
481                            keys_to_remove.push(key.clone());
482                        }
483                    }
484                    for key in keys_to_remove {
485                        store.map.remove(&key);
486                        if let Some(pos) = store.order.iter().position(|k| k == &key) {
487                            store.order.remove(pos);
488                        }
489                    }
490                }
491                CacheStore::Lfu(store) => {
492                    let mut keys_to_remove = Vec::new();
493                    for (key, entry) in &mut store.map {
494                        if !f(key, entry) {
495                            keys_to_remove.push(key.clone());
496                        }
497                    }
498                    for key in keys_to_remove {
499                        store.map.remove(&key);
500                        store.frequencies.remove(&key);
501                    }
502                }
503            }
504        }
505
506        fn len(&self) -> usize {
507            match self {
508                CacheStore::Unbounded(store) => store.map.len(),
509                CacheStore::Lru(store) => store.map.len(),
510                CacheStore::Lfu(store) => store.map.len(),
511            }
512        }
513    }
514
515    /// 内存缓存后端
516    pub struct MemoryCacheBackend {
517        config: CacheConfig,
518        store: Arc<RwLock<CacheStore>>,
519    }
520
521    impl MemoryCacheBackend {
522        /// 创建新的内存缓存实例
523        pub fn new(config: CacheConfig) -> Self {
524            let store = match config.eviction_policy {
525                EvictionPolicy::None => CacheStore::Unbounded(UnboundedStore::new()),
526                EvictionPolicy::Lru => CacheStore::Lru(LruStore::new(config.max_capacity)),
527                EvictionPolicy::Lfu => CacheStore::Lfu(LfuStore::new(config.max_capacity)),
528            };
529            Self { config, store: Arc::new(RwLock::new(store)) }
530        }
531
532        fn build_key(&self, key: &str) -> String {
533            if self.config.key_prefix.is_empty() { key.to_string() } else { format!("{}:{}", self.config.key_prefix, key) }
534        }
535    }
536
537    #[async_trait::async_trait]
538    impl CacheBackend for MemoryCacheBackend {
539        async fn get_bytes(&self, key: &str) -> CacheResult<Option<Vec<u8>>> {
540            let full_key = self.build_key(key);
541            let mut store = self.store.write().await;
542
543            if let Some(entry) = store.get(&full_key) {
544                if entry.is_expired() {
545                    store.remove(&full_key);
546                    return Ok(None);
547                }
548                return Ok(Some(entry.data.clone()));
549            }
550            Ok(None)
551        }
552
553        async fn set_bytes(&self, key: &str, value: &[u8], ttl: Option<Duration>) -> CacheResult<()> {
554            let full_key = self.build_key(key);
555            let effective_ttl = ttl.or(self.config.default_ttl);
556            let expires_at = effective_ttl.map(|d| Instant::now() + d);
557
558            let entry = CacheEntry { data: value.to_vec(), expires_at };
559            let mut store = self.store.write().await;
560            store.insert(full_key, entry);
561            Ok(())
562        }
563
564        async fn delete(&self, key: &str) -> CacheResult<bool> {
565            let full_key = self.build_key(key);
566            let mut store = self.store.write().await;
567            Ok(store.remove(&full_key).is_some())
568        }
569
570        async fn exists(&self, key: &str) -> CacheResult<bool> {
571            let full_key = self.build_key(key);
572            let mut store = self.store.write().await;
573            if let Some(entry) = store.get(&full_key) {
574                if entry.is_expired() {
575                    store.remove(&full_key);
576                    return Ok(false);
577                }
578                return Ok(true);
579            }
580            Ok(false)
581        }
582
583        async fn expire(&self, key: &str, ttl: Duration) -> CacheResult<bool> {
584            let full_key = self.build_key(key);
585            let mut store = self.store.write().await;
586            if let Some(entry) = store.get_mut(&full_key) {
587                if entry.is_expired() {
588                    store.remove(&full_key);
589                    return Ok(false);
590                }
591                entry.expires_at = Some(Instant::now() + ttl);
592                return Ok(true);
593            }
594            Ok(false)
595        }
596
597        async fn ttl(&self, key: &str) -> CacheResult<Option<Duration>> {
598            let full_key = self.build_key(key);
599            let mut store = self.store.write().await;
600            if let Some(entry) = store.get(&full_key) {
601                if entry.is_expired() {
602                    store.remove(&full_key);
603                    return Ok(None);
604                }
605                if let Some(expires_at) = entry.expires_at {
606                    let now = Instant::now();
607                    if expires_at > now {
608                        return Ok(Some(expires_at - now));
609                    }
610                }
611            }
612            Ok(None)
613        }
614
615        async fn mget_bytes(&self, keys: &[&str]) -> CacheResult<Vec<Option<Vec<u8>>>> {
616            let mut results = Vec::with_capacity(keys.len());
617            for key in keys {
618                results.push(self.get_bytes(key).await?);
619            }
620            Ok(results)
621        }
622
623        async fn mset_bytes(&self, items: &[(&str, &[u8])], ttl: Option<Duration>) -> CacheResult<()> {
624            for (key, value) in items {
625                self.set_bytes(key, value, ttl).await?;
626            }
627            Ok(())
628        }
629
630        async fn mdelete(&self, keys: &[&str]) -> CacheResult<u64> {
631            let mut count = 0u64;
632            for key in keys {
633                if self.delete(key).await? {
634                    count += 1;
635                }
636            }
637            Ok(count)
638        }
639
640        async fn incr(&self, key: &str, delta: i64) -> CacheResult<i64> {
641            let full_key = self.build_key(key);
642            let mut store = self.store.write().await;
643
644            if !store.contains_key(&full_key) {
645                store.insert(full_key.clone(), CacheEntry { data: b"0".to_vec(), expires_at: None });
646            }
647
648            let entry = store.get_mut(&full_key).unwrap();
649            let mut value: i64 = String::from_utf8_lossy(&entry.data).parse().unwrap_or(0);
650            value += delta;
651            entry.data = value.to_string().into_bytes();
652            Ok(value)
653        }
654
655        async fn decr(&self, key: &str, delta: i64) -> CacheResult<i64> {
656            self.incr(key, -delta).await
657        }
658
659        async fn clear(&self) -> CacheResult<()> {
660            let mut store = self.store.write().await;
661            if self.config.key_prefix.is_empty() {
662                store.clear();
663            }
664            else {
665                let prefix = format!("{}:", self.config.key_prefix);
666                store.retain(|k, _| !k.starts_with(&prefix));
667            }
668            Ok(())
669        }
670
671        fn config(&self) -> &CacheConfig {
672            &self.config
673        }
674    }
675}
676
677/// 便捷函数:创建内存缓存服务
678pub fn memory_cache(config: CacheConfig) -> CacheService {
679    CacheService::new(Box::new(memory::MemoryCacheBackend::new(config)))
680}
681
682#[cfg(feature = "redis")]
683/// 便捷函数:创建 Redis 缓存服务
684pub fn redis_cache(redis_config: redis::RedisConfig, cache_config: CacheConfig) -> CacheResult<CacheService> {
685    let backend = redis::RedisCacheBackend::new(redis_config, cache_config)?;
686    Ok(CacheService::new(Box::new(backend)))
687}