oxihuman_core/
counter_map.rs1#![allow(dead_code)]
4
5use std::collections::HashMap;
6
7#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct CounterMap {
11 counts: HashMap<String, u64>,
12}
13
14#[allow(dead_code)]
15impl CounterMap {
16 pub fn new() -> Self {
17 Self {
18 counts: HashMap::new(),
19 }
20 }
21
22 pub fn increment(&mut self, key: &str) -> u64 {
23 let entry = self.counts.entry(key.to_string()).or_insert(0);
24 *entry += 1;
25 *entry
26 }
27
28 pub fn decrement(&mut self, key: &str) -> u64 {
29 let entry = self.counts.entry(key.to_string()).or_insert(0);
30 *entry = entry.saturating_sub(1);
31 *entry
32 }
33
34 pub fn get(&self, key: &str) -> u64 {
35 self.counts.get(key).copied().unwrap_or(0)
36 }
37
38 pub fn set(&mut self, key: &str, count: u64) {
39 self.counts.insert(key.to_string(), count);
40 }
41
42 pub fn total(&self) -> u64 {
43 self.counts.values().sum()
44 }
45
46 pub fn len(&self) -> usize {
47 self.counts.len()
48 }
49
50 pub fn is_empty(&self) -> bool {
51 self.counts.is_empty()
52 }
53
54 pub fn max_key(&self) -> Option<&str> {
55 self.counts
56 .iter()
57 .max_by_key(|(_, &v)| v)
58 .map(|(k, _)| k.as_str())
59 }
60
61 pub fn min_key(&self) -> Option<&str> {
62 self.counts
63 .iter()
64 .min_by_key(|(_, &v)| v)
65 .map(|(k, _)| k.as_str())
66 }
67
68 pub fn remove(&mut self, key: &str) -> Option<u64> {
69 self.counts.remove(key)
70 }
71
72 pub fn clear(&mut self) {
73 self.counts.clear();
74 }
75
76 pub fn keys(&self) -> Vec<&str> {
77 self.counts.keys().map(|k| k.as_str()).collect()
78 }
79}
80
81impl Default for CounterMap {
82 fn default() -> Self {
83 Self::new()
84 }
85}
86
87#[cfg(test)]
88mod tests {
89 use super::*;
90
91 #[test]
92 fn test_new() {
93 let cm = CounterMap::new();
94 assert!(cm.is_empty());
95 }
96
97 #[test]
98 fn test_increment() {
99 let mut cm = CounterMap::new();
100 assert_eq!(cm.increment("a"), 1);
101 assert_eq!(cm.increment("a"), 2);
102 }
103
104 #[test]
105 fn test_decrement() {
106 let mut cm = CounterMap::new();
107 cm.set("a", 5);
108 assert_eq!(cm.decrement("a"), 4);
109 }
110
111 #[test]
112 fn test_decrement_floor() {
113 let mut cm = CounterMap::new();
114 assert_eq!(cm.decrement("x"), 0);
115 }
116
117 #[test]
118 fn test_get_missing() {
119 let cm = CounterMap::new();
120 assert_eq!(cm.get("nope"), 0);
121 }
122
123 #[test]
124 fn test_total() {
125 let mut cm = CounterMap::new();
126 cm.set("a", 10);
127 cm.set("b", 20);
128 assert_eq!(cm.total(), 30);
129 }
130
131 #[test]
132 fn test_max_key() {
133 let mut cm = CounterMap::new();
134 cm.set("a", 1);
135 cm.set("b", 5);
136 cm.set("c", 3);
137 assert_eq!(cm.max_key(), Some("b"));
138 }
139
140 #[test]
141 fn test_min_key() {
142 let mut cm = CounterMap::new();
143 cm.set("a", 10);
144 cm.set("b", 2);
145 assert_eq!(cm.min_key(), Some("b"));
146 }
147
148 #[test]
149 fn test_remove() {
150 let mut cm = CounterMap::new();
151 cm.set("k", 5);
152 assert_eq!(cm.remove("k"), Some(5));
153 assert!(cm.is_empty());
154 }
155
156 #[test]
157 fn test_clear() {
158 let mut cm = CounterMap::new();
159 cm.increment("a");
160 cm.increment("b");
161 cm.clear();
162 assert!(cm.is_empty());
163 }
164}