1use std::sync::Arc;
9
10pub trait CacheMetrics: Send + Sync {
12 fn hits(&self) -> u64;
14
15 fn misses(&self) -> u64;
17
18 fn hit_rate(&self) -> f64 {
20 let total = self.hits() + self.misses();
21 if total == 0 {
22 0.0
23 } else {
24 (self.hits() as f64 / total as f64) * 100.0
25 }
26 }
27}
28
29pub trait AuthzCache<V: Clone + Send + Sync>: Send + Sync {
34 fn get(&self, key: &str) -> Option<V>;
36
37 fn insert(&self, key: &str, value: V);
39
40 fn invalidate(&self, key: &str);
42
43 fn invalidate_all(&self);
45
46 fn metrics(&self) -> Box<dyn CacheMetrics>;
48}
49
50pub struct NoopCache;
54
55struct NoopMetrics;
57
58impl CacheMetrics for NoopMetrics {
59 fn hits(&self) -> u64 {
60 0
61 }
62
63 fn misses(&self) -> u64 {
64 0
65 }
66}
67
68impl<V: Clone + Send + Sync> AuthzCache<V> for NoopCache {
69 fn get(&self, _key: &str) -> Option<V> {
70 None
71 }
72
73 fn insert(&self, _key: &str, _value: V) {}
74
75 fn invalidate(&self, _key: &str) {}
76
77 fn invalidate_all(&self) {}
78
79 fn metrics(&self) -> Box<dyn CacheMetrics> {
80 Box::new(NoopMetrics)
81 }
82}
83
84pub fn noop_cache<V: Clone + Send + Sync + 'static>() -> Arc<dyn AuthzCache<V>> {
86 Arc::new(NoopCache)
87}
88
89#[cfg(test)]
90mod tests {
91 use super::*;
92
93 #[test]
94 fn noop_cache_always_misses() {
95 let cache: Arc<dyn AuthzCache<String>> = noop_cache();
96 cache.insert("key", "value".to_string());
97 assert_eq!(cache.get("key"), None);
98 }
99
100 #[test]
101 fn noop_cache_invalidate_is_safe() {
102 let cache: Arc<dyn AuthzCache<i32>> = noop_cache();
103 cache.invalidate_all(); }
105}