Skip to main content

crates_docs/tools/docs/
cache.rs

1//! Document cache module
2
3use crate::cache::Cache;
4use std::sync::Arc;
5use std::time::Duration;
6
7/// Document cache service
8#[derive(Clone)]
9pub struct DocCache {
10    cache: Arc<dyn Cache>,
11}
12
13impl DocCache {
14    /// Create a new document cache
15    pub fn new(cache: Arc<dyn Cache>) -> Self {
16        Self { cache }
17    }
18
19    /// Get cached document
20    pub async fn get_crate_docs(&self, crate_name: &str, version: Option<&str>) -> Option<String> {
21        let key = Self::crate_cache_key(crate_name, version);
22        self.cache.get(&key).await
23    }
24
25    /// Set cached document
26    ///
27    /// # Errors
28    ///
29    /// Returns an error if the cache operation fails
30    pub async fn set_crate_docs(
31        &self,
32        crate_name: &str,
33        version: Option<&str>,
34        content: String,
35    ) -> crate::error::Result<()> {
36        let key = Self::crate_cache_key(crate_name, version);
37        self.cache
38            .set(key, content, Some(Duration::from_secs(3600)))
39            .await
40    }
41
42    /// Get cached search results
43    pub async fn get_search_results(&self, query: &str, limit: u32) -> Option<String> {
44        let key = Self::search_cache_key(query, limit);
45        self.cache.get(&key).await
46    }
47
48    /// Set cached search results
49    ///
50    /// # Errors
51    ///
52    /// Returns an error if the cache operation fails
53    pub async fn set_search_results(
54        &self,
55        query: &str,
56        limit: u32,
57        content: String,
58    ) -> crate::error::Result<()> {
59        let key = Self::search_cache_key(query, limit);
60        self.cache
61            .set(key, content, Some(Duration::from_secs(300)))
62            .await // 5 minutes cache
63    }
64
65    /// Get cached item documentation
66    pub async fn get_item_docs(
67        &self,
68        crate_name: &str,
69        item_path: &str,
70        version: Option<&str>,
71    ) -> Option<String> {
72        let key = Self::item_cache_key(crate_name, item_path, version);
73        self.cache.get(&key).await
74    }
75
76    /// Set cached item documentation
77    ///
78    /// # Errors
79    ///
80    /// Returns an error if the cache operation fails
81    pub async fn set_item_docs(
82        &self,
83        crate_name: &str,
84        item_path: &str,
85        version: Option<&str>,
86        content: String,
87    ) -> crate::error::Result<()> {
88        let key = Self::item_cache_key(crate_name, item_path, version);
89        self.cache
90            .set(key, content, Some(Duration::from_secs(1800)))
91            .await // 30 minutes cache
92    }
93
94    /// Clear cache
95    ///
96    /// # Errors
97    ///
98    /// Returns an error if the cache operation fails
99    pub async fn clear(&self) -> crate::error::Result<()> {
100        self.cache.clear().await
101    }
102
103    /// Build crate cache key
104    fn crate_cache_key(crate_name: &str, version: Option<&str>) -> String {
105        if let Some(ver) = version {
106            format!("crate:{crate_name}:{ver}")
107        } else {
108            format!("crate:{crate_name}")
109        }
110    }
111
112    /// Build search cache key
113    fn search_cache_key(query: &str, limit: u32) -> String {
114        format!("search:{query}:{limit}")
115    }
116
117    /// Build item cache key
118    fn item_cache_key(crate_name: &str, item_path: &str, version: Option<&str>) -> String {
119        if let Some(ver) = version {
120            format!("item:{crate_name}:{ver}:{item_path}")
121        } else {
122            format!("item:{crate_name}:{item_path}")
123        }
124    }
125}
126
127impl Default for DocCache {
128    fn default() -> Self {
129        let cache = Arc::new(crate::cache::memory::MemoryCache::new(1000));
130        Self::new(cache)
131    }
132}
133
134#[cfg(test)]
135mod tests {
136    use super::*;
137    use crate::cache::memory::MemoryCache;
138
139    #[tokio::test]
140    async fn test_doc_cache() {
141        let memory_cache = MemoryCache::new(100);
142        let cache = Arc::new(memory_cache);
143        let doc_cache = DocCache::new(cache);
144
145        // 测试 crate 文档缓存
146        doc_cache
147            .set_crate_docs("serde", Some("1.0"), "Test docs".to_string())
148            .await
149            .expect("set_crate_docs should succeed");
150        let cached = doc_cache.get_crate_docs("serde", Some("1.0")).await;
151        assert_eq!(cached, Some("Test docs".to_string()));
152
153        // 测试搜索结果缓存
154        doc_cache
155            .set_search_results("web framework", 10, "Search results".to_string())
156            .await
157            .expect("set_search_results should succeed");
158        let search_cached = doc_cache.get_search_results("web framework", 10).await;
159        assert_eq!(search_cached, Some("Search results".to_string()));
160
161        // 测试项目文档缓存
162        doc_cache
163            .set_item_docs(
164                "serde",
165                "serde::Serialize",
166                Some("1.0"),
167                "Item docs".to_string(),
168            )
169            .await
170            .expect("set_item_docs should succeed");
171        let item_cached = doc_cache
172            .get_item_docs("serde", "serde::Serialize", Some("1.0"))
173            .await;
174        assert_eq!(item_cached, Some("Item docs".to_string()));
175
176        // 测试清理
177        doc_cache.clear().await.expect("clear should succeed");
178        let cleared = doc_cache.get_crate_docs("serde", Some("1.0")).await;
179        assert_eq!(cleared, None);
180    }
181
182    #[test]
183    fn test_cache_key_generation() {
184        assert_eq!(DocCache::crate_cache_key("serde", None), "crate:serde");
185        assert_eq!(
186            DocCache::crate_cache_key("serde", Some("1.0")),
187            "crate:serde:1.0"
188        );
189
190        assert_eq!(
191            DocCache::search_cache_key("web framework", 10),
192            "search:web framework:10"
193        );
194
195        assert_eq!(
196            DocCache::item_cache_key("serde", "Serialize", None),
197            "item:serde:Serialize"
198        );
199        assert_eq!(
200            DocCache::item_cache_key("serde", "Serialize", Some("1.0")),
201            "item:serde:1.0:Serialize"
202        );
203    }
204}