oxihuman_core/
option_cache.rs1#![allow(dead_code)]
4
5use std::collections::HashMap;
6
7#[allow(dead_code)]
9pub struct OptionCache {
10 present: HashMap<String, String>,
11 absent: std::collections::HashSet<String>,
12 hits: u64,
13 misses: u64,
14}
15
16#[allow(dead_code)]
17impl OptionCache {
18 pub fn new() -> Self {
19 Self {
20 present: HashMap::new(),
21 absent: std::collections::HashSet::new(),
22 hits: 0,
23 misses: 0,
24 }
25 }
26 pub fn set_some(&mut self, key: &str, value: &str) {
27 self.absent.remove(key);
28 self.present.insert(key.to_string(), value.to_string());
29 }
30 pub fn set_none(&mut self, key: &str) {
31 self.present.remove(key);
32 self.absent.insert(key.to_string());
33 }
34 pub fn get(&mut self, key: &str) -> Option<Option<&str>> {
35 if let Some(v) = self.present.get(key) {
36 self.hits += 1;
37 Some(Some(v.as_str()))
38 } else if self.absent.contains(key) {
39 self.hits += 1;
40 Some(None)
41 } else {
42 self.misses += 1;
43 None
44 }
45 }
46 pub fn has_key(&self, key: &str) -> bool {
47 self.present.contains_key(key) || self.absent.contains(key)
48 }
49 pub fn remove(&mut self, key: &str) -> bool {
50 self.present.remove(key).is_some() || self.absent.remove(key)
51 }
52 pub fn len(&self) -> usize {
53 self.present.len() + self.absent.len()
54 }
55 pub fn is_empty(&self) -> bool {
56 self.present.is_empty() && self.absent.is_empty()
57 }
58 pub fn hits(&self) -> u64 {
59 self.hits
60 }
61 pub fn misses(&self) -> u64 {
62 self.misses
63 }
64 pub fn hit_rate(&self) -> f32 {
65 let total = self.hits + self.misses;
66 if total == 0 {
67 0.0
68 } else {
69 self.hits as f32 / total as f32
70 }
71 }
72 pub fn clear(&mut self) {
73 self.present.clear();
74 self.absent.clear();
75 }
76 pub fn present_count(&self) -> usize {
77 self.present.len()
78 }
79 pub fn absent_count(&self) -> usize {
80 self.absent.len()
81 }
82}
83
84impl Default for OptionCache {
85 fn default() -> Self {
86 Self::new()
87 }
88}
89
90#[allow(dead_code)]
91pub fn new_option_cache() -> OptionCache {
92 OptionCache::new()
93}
94#[allow(dead_code)]
95pub fn oc_set_some(c: &mut OptionCache, key: &str, value: &str) {
96 c.set_some(key, value);
97}
98#[allow(dead_code)]
99pub fn oc_set_none(c: &mut OptionCache, key: &str) {
100 c.set_none(key);
101}
102#[allow(dead_code)]
103pub fn oc_get<'a>(c: &'a mut OptionCache, key: &str) -> Option<Option<&'a str>> {
104 c.get(key)
105}
106#[allow(dead_code)]
107pub fn oc_has_key(c: &OptionCache, key: &str) -> bool {
108 c.has_key(key)
109}
110#[allow(dead_code)]
111pub fn oc_remove(c: &mut OptionCache, key: &str) -> bool {
112 c.remove(key)
113}
114#[allow(dead_code)]
115pub fn oc_len(c: &OptionCache) -> usize {
116 c.len()
117}
118#[allow(dead_code)]
119pub fn oc_is_empty(c: &OptionCache) -> bool {
120 c.is_empty()
121}
122#[allow(dead_code)]
123pub fn oc_hit_rate(c: &OptionCache) -> f32 {
124 c.hit_rate()
125}
126#[allow(dead_code)]
127pub fn oc_clear(c: &mut OptionCache) {
128 c.clear();
129}
130
131#[cfg(test)]
132mod tests {
133 use super::*;
134 #[test]
135 fn test_set_some_get() {
136 let mut c = new_option_cache();
137 oc_set_some(&mut c, "k", "v");
138 assert_eq!(oc_get(&mut c, "k"), Some(Some("v")));
139 }
140 #[test]
141 fn test_set_none_get() {
142 let mut c = new_option_cache();
143 oc_set_none(&mut c, "k");
144 assert_eq!(oc_get(&mut c, "k"), Some(None));
145 }
146 #[test]
147 fn test_miss() {
148 let mut c = new_option_cache();
149 assert_eq!(oc_get(&mut c, "missing"), None);
150 }
151 #[test]
152 fn test_has_key() {
153 let mut c = new_option_cache();
154 oc_set_some(&mut c, "a", "1");
155 assert!(oc_has_key(&c, "a"));
156 assert!(!oc_has_key(&c, "b"));
157 }
158 #[test]
159 fn test_remove() {
160 let mut c = new_option_cache();
161 oc_set_some(&mut c, "x", "y");
162 assert!(oc_remove(&mut c, "x"));
163 assert!(!oc_has_key(&c, "x"));
164 }
165 #[test]
166 fn test_hit_rate() {
167 let mut c = new_option_cache();
168 oc_set_some(&mut c, "k", "v");
169 oc_get(&mut c, "k");
170 oc_get(&mut c, "missing");
171 let r = oc_hit_rate(&c);
172 assert!((0.0..=1.0).contains(&r));
173 }
174 #[test]
175 fn test_len() {
176 let mut c = new_option_cache();
177 oc_set_some(&mut c, "a", "1");
178 oc_set_none(&mut c, "b");
179 assert_eq!(oc_len(&c), 2);
180 }
181 #[test]
182 fn test_clear() {
183 let mut c = new_option_cache();
184 oc_set_some(&mut c, "a", "1");
185 oc_clear(&mut c);
186 assert!(oc_is_empty(&c));
187 }
188 #[test]
189 fn test_present_absent_counts() {
190 let mut c = new_option_cache();
191 oc_set_some(&mut c, "a", "1");
192 oc_set_none(&mut c, "b");
193 assert_eq!(c.present_count(), 1);
194 assert_eq!(c.absent_count(), 1);
195 }
196 #[test]
197 fn test_overwrite_some_to_none() {
198 let mut c = new_option_cache();
199 oc_set_some(&mut c, "k", "v");
200 oc_set_none(&mut c, "k");
201 assert_eq!(c.present_count(), 0);
202 assert_eq!(c.absent_count(), 1);
203 }
204}