unistore_cache/
entry.rs

1//! 【缓存条目】- 单个缓存条目
2//!
3//! 职责:
4//! - 包装缓存值和元数据
5//! - 管理过期时间
6
7use crate::deps::{Duration, Instant};
8
9/// 缓存条目
10#[derive(Debug, Clone)]
11pub struct CacheEntry<V> {
12    /// 缓存值
13    value: V,
14    /// 创建时间
15    created_at: Instant,
16    /// 最后访问时间
17    last_accessed: Instant,
18    /// 过期时间(None 表示永不过期)
19    expires_at: Option<Instant>,
20    /// 访问次数
21    access_count: u64,
22}
23
24impl<V> CacheEntry<V> {
25    /// 创建新条目
26    pub fn new(value: V, ttl: Option<Duration>) -> Self {
27        let now = Instant::now();
28        Self {
29            value,
30            created_at: now,
31            last_accessed: now,
32            expires_at: ttl.map(|t| now + t),
33            access_count: 0,
34        }
35    }
36
37    /// 获取值的引用
38    pub fn value(&self) -> &V {
39        &self.value
40    }
41
42    /// 获取值的可变引用
43    pub fn value_mut(&mut self) -> &mut V {
44        &mut self.value
45    }
46
47    /// 取出值
48    pub fn into_value(self) -> V {
49        self.value
50    }
51
52    /// 检查是否已过期
53    pub fn is_expired(&self) -> bool {
54        self.expires_at
55            .map(|exp| Instant::now() > exp)
56            .unwrap_or(false)
57    }
58
59    /// 获取剩余 TTL
60    pub fn remaining_ttl(&self) -> Option<Duration> {
61        self.expires_at.and_then(|exp| {
62            let now = Instant::now();
63            if now < exp {
64                Some(exp - now)
65            } else {
66                None
67            }
68        })
69    }
70
71    /// 更新最后访问时间
72    pub fn touch(&mut self) {
73        self.last_accessed = Instant::now();
74        self.access_count += 1;
75    }
76
77    /// 获取最后访问时间
78    pub fn last_accessed(&self) -> Instant {
79        self.last_accessed
80    }
81
82    /// 获取创建时间
83    pub fn created_at(&self) -> Instant {
84        self.created_at
85    }
86
87    /// 获取访问次数
88    pub fn access_count(&self) -> u64 {
89        self.access_count
90    }
91
92    /// 获取存活时间
93    pub fn age(&self) -> Duration {
94        self.created_at.elapsed()
95    }
96
97    /// 延长 TTL
98    pub fn extend_ttl(&mut self, duration: Duration) {
99        if let Some(exp) = self.expires_at.as_mut() {
100            *exp = *exp + duration;
101        }
102    }
103
104    /// 设置新的过期时间
105    pub fn set_ttl(&mut self, ttl: Option<Duration>) {
106        self.expires_at = ttl.map(|t| Instant::now() + t);
107    }
108}
109
110#[cfg(test)]
111mod tests {
112    use super::*;
113
114    #[test]
115    fn test_entry_creation() {
116        let entry = CacheEntry::new("value", Some(Duration::from_secs(10)));
117        assert_eq!(entry.value(), &"value");
118        assert!(!entry.is_expired());
119    }
120
121    #[test]
122    fn test_entry_no_ttl() {
123        let entry = CacheEntry::new(42, None);
124        assert!(!entry.is_expired());
125        assert!(entry.remaining_ttl().is_none());
126    }
127
128    #[test]
129    fn test_entry_touch() {
130        let mut entry = CacheEntry::new("value", None);
131        assert_eq!(entry.access_count(), 0);
132
133        entry.touch();
134        assert_eq!(entry.access_count(), 1);
135
136        entry.touch();
137        assert_eq!(entry.access_count(), 2);
138    }
139}