1use super::SystemInfo;
4use std::time::{Duration, Instant};
5
6#[derive(Debug, Clone)]
8pub struct CacheEntry {
9 pub info: SystemInfo,
11 pub cached_at: Instant,
13}
14
15#[derive(Debug, Default)]
17pub struct SystemInfoCache {
18 entry: Option<CacheEntry>,
19}
20
21impl SystemInfoCache {
22 pub fn new() -> Self {
24 Self { entry: None }
25 }
26
27 pub fn get_if_valid(&self, ttl: Duration) -> Option<&SystemInfo> {
29 self.entry.as_ref().and_then(|entry| {
30 if entry.cached_at.elapsed() < ttl {
31 Some(&entry.info)
32 } else {
33 None
34 }
35 })
36 }
37
38 pub fn set(&mut self, info: SystemInfo) {
40 self.entry = Some(CacheEntry {
41 info,
42 cached_at: Instant::now(),
43 });
44 }
45
46 pub fn invalidate(&mut self) {
48 self.entry = None;
49 }
50
51 pub fn is_valid(&self, ttl: Duration) -> bool {
53 self.entry
54 .as_ref()
55 .map(|e| e.cached_at.elapsed() < ttl)
56 .unwrap_or(false)
57 }
58
59 pub fn age(&self) -> Option<Duration> {
61 self.entry.as_ref().map(|e| e.cached_at.elapsed())
62 }
63}
64
65#[cfg(test)]
66mod tests {
67 use super::*;
68 use std::thread::sleep;
69
70 fn create_test_info() -> SystemInfo {
71 SystemInfo {
72 os: super::super::OsInfo {
73 name: "test".to_string(),
74 version: "1.0".to_string(),
75 arch: "x86_64".to_string(),
76 family: "unix".to_string(),
77 },
78 shell: super::super::ShellInfo {
79 name: "bash".to_string(),
80 version: Some("5.0".to_string()),
81 path: std::path::PathBuf::from("/bin/bash"),
82 },
83 languages: vec![],
84 package_managers: vec![],
85 project: None,
86 git: None,
87 build_tools: vec![],
88 test_frameworks: vec![],
89 collected_at: std::time::SystemTime::now(),
90 }
91 }
92
93 #[test]
94 fn test_cache_empty() {
95 let cache = SystemInfoCache::new();
96 assert!(cache.get_if_valid(Duration::from_secs(60)).is_none());
97 assert!(!cache.is_valid(Duration::from_secs(60)));
98 }
99
100 #[test]
101 fn test_cache_set_get() {
102 let mut cache = SystemInfoCache::new();
103 let info = create_test_info();
104
105 cache.set(info);
106
107 assert!(cache.get_if_valid(Duration::from_secs(60)).is_some());
108 assert!(cache.is_valid(Duration::from_secs(60)));
109 }
110
111 #[test]
112 fn test_cache_invalidate() {
113 let mut cache = SystemInfoCache::new();
114 cache.set(create_test_info());
115
116 cache.invalidate();
117
118 assert!(cache.get_if_valid(Duration::from_secs(60)).is_none());
119 }
120
121 #[test]
122 fn test_cache_ttl_expiry() {
123 let mut cache = SystemInfoCache::new();
124 cache.set(create_test_info());
125
126 sleep(Duration::from_millis(10));
128
129 assert!(cache.get_if_valid(Duration::from_millis(1)).is_none());
130 assert!(!cache.is_valid(Duration::from_millis(1)));
131 }
132}