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    pub async fn set_crate_docs(&self, crate_name: &str, version: Option<&str>, content: String) {
27        let key = Self::crate_cache_key(crate_name, version);
28        self.cache
29            .set(key, content, Some(Duration::from_secs(3600)))
30            .await;
31    }
32
33    /// Get cached search results
34    pub async fn get_search_results(&self, query: &str, limit: u32) -> Option<String> {
35        let key = Self::search_cache_key(query, limit);
36        self.cache.get(&key).await
37    }
38
39    /// Set cached search results
40    pub async fn set_search_results(&self, query: &str, limit: u32, content: String) {
41        let key = Self::search_cache_key(query, limit);
42        self.cache
43            .set(key, content, Some(Duration::from_secs(300)))
44            .await; // 5 minutes cache
45    }
46
47    /// Get cached item documentation
48    pub async fn get_item_docs(
49        &self,
50        crate_name: &str,
51        item_path: &str,
52        version: Option<&str>,
53    ) -> Option<String> {
54        let key = Self::item_cache_key(crate_name, item_path, version);
55        self.cache.get(&key).await
56    }
57
58    /// Set cached item documentation
59    pub async fn set_item_docs(
60        &self,
61        crate_name: &str,
62        item_path: &str,
63        version: Option<&str>,
64        content: String,
65    ) {
66        let key = Self::item_cache_key(crate_name, item_path, version);
67        self.cache
68            .set(key, content, Some(Duration::from_secs(1800)))
69            .await; // 30 minutes cache
70    }
71
72    /// Clear cache
73    pub async fn clear(&self) {
74        self.cache.clear().await;
75    }
76
77    /// Build crate cache key
78    fn crate_cache_key(crate_name: &str, version: Option<&str>) -> String {
79        if let Some(ver) = version {
80            format!("crate:{crate_name}:{ver}")
81        } else {
82            format!("crate:{crate_name}")
83        }
84    }
85
86    /// Build search cache key
87    fn search_cache_key(query: &str, limit: u32) -> String {
88        format!("search:{query}:{limit}")
89    }
90
91    /// Build item cache key
92    fn item_cache_key(crate_name: &str, item_path: &str, version: Option<&str>) -> String {
93        if let Some(ver) = version {
94            format!("item:{crate_name}:{ver}:{item_path}")
95        } else {
96            format!("item:{crate_name}:{item_path}")
97        }
98    }
99}
100
101impl Default for DocCache {
102    fn default() -> Self {
103        let cache = Arc::new(crate::cache::memory::MemoryCache::new(1000));
104        Self::new(cache)
105    }
106}
107
108#[cfg(test)]
109mod tests {
110    use super::*;
111    use crate::cache::memory::MemoryCache;
112
113    #[tokio::test]
114    async fn test_doc_cache() {
115        let memory_cache = MemoryCache::new(100);
116        let cache = Arc::new(memory_cache);
117        let doc_cache = DocCache::new(cache);
118
119        // 测试 crate 文档缓存
120        doc_cache
121            .set_crate_docs("serde", Some("1.0"), "Test docs".to_string())
122            .await;
123        let cached = doc_cache.get_crate_docs("serde", Some("1.0")).await;
124        assert_eq!(cached, Some("Test docs".to_string()));
125
126        // 测试搜索结果缓存
127        doc_cache
128            .set_search_results("web framework", 10, "Search results".to_string())
129            .await;
130        let search_cached = doc_cache.get_search_results("web framework", 10).await;
131        assert_eq!(search_cached, Some("Search results".to_string()));
132
133        // 测试项目文档缓存
134        doc_cache
135            .set_item_docs(
136                "serde",
137                "serde::Serialize",
138                Some("1.0"),
139                "Item docs".to_string(),
140            )
141            .await;
142        let item_cached = doc_cache
143            .get_item_docs("serde", "serde::Serialize", Some("1.0"))
144            .await;
145        assert_eq!(item_cached, Some("Item docs".to_string()));
146
147        // 测试清理
148        doc_cache.clear().await;
149        let cleared = doc_cache.get_crate_docs("serde", Some("1.0")).await;
150        assert_eq!(cleared, None);
151    }
152
153    #[test]
154    fn test_cache_key_generation() {
155        assert_eq!(DocCache::crate_cache_key("serde", None), "crate:serde");
156        assert_eq!(
157            DocCache::crate_cache_key("serde", Some("1.0")),
158            "crate:serde:1.0"
159        );
160
161        assert_eq!(
162            DocCache::search_cache_key("web framework", 10),
163            "search:web framework:10"
164        );
165
166        assert_eq!(
167            DocCache::item_cache_key("serde", "Serialize", None),
168            "item:serde:Serialize"
169        );
170        assert_eq!(
171            DocCache::item_cache_key("serde", "Serialize", Some("1.0")),
172            "item:serde:1.0:Serialize"
173        );
174    }
175}