oxihuman_core/
selector_map.rs1#![allow(dead_code)]
4
5use std::collections::HashMap;
8
9#[allow(dead_code)]
11pub struct SelectorMap<V> {
12 entries: HashMap<String, V>,
13 selected: Option<String>,
14 change_count: u64,
15}
16
17#[allow(dead_code)]
18impl<V: Clone> SelectorMap<V> {
19 pub fn new() -> Self {
20 Self {
21 entries: HashMap::new(),
22 selected: None,
23 change_count: 0,
24 }
25 }
26
27 pub fn insert(&mut self, key: &str, value: V) {
28 self.entries.insert(key.to_string(), value);
29 self.change_count += 1;
30 }
31
32 pub fn remove(&mut self, key: &str) -> bool {
33 if self.entries.remove(key).is_some() {
34 if self.selected.as_deref() == Some(key) {
35 self.selected = None;
36 }
37 self.change_count += 1;
38 true
39 } else {
40 false
41 }
42 }
43
44 pub fn select(&mut self, key: &str) -> bool {
45 if self.entries.contains_key(key) {
46 self.selected = Some(key.to_string());
47 self.change_count += 1;
48 true
49 } else {
50 false
51 }
52 }
53
54 pub fn deselect(&mut self) {
55 self.selected = None;
56 }
57
58 pub fn selected_key(&self) -> Option<&str> {
59 self.selected.as_deref()
60 }
61
62 pub fn selected_value(&self) -> Option<&V> {
63 self.selected.as_ref().and_then(|k| self.entries.get(k))
64 }
65
66 pub fn get(&self, key: &str) -> Option<&V> {
67 self.entries.get(key)
68 }
69
70 pub fn contains(&self, key: &str) -> bool {
71 self.entries.contains_key(key)
72 }
73
74 pub fn len(&self) -> usize {
75 self.entries.len()
76 }
77
78 pub fn is_empty(&self) -> bool {
79 self.entries.is_empty()
80 }
81
82 pub fn keys(&self) -> Vec<&str> {
83 let mut v: Vec<&str> = self.entries.keys().map(|s| s.as_str()).collect();
84 v.sort_unstable();
85 v
86 }
87
88 pub fn change_count(&self) -> u64 {
89 self.change_count
90 }
91
92 pub fn clear(&mut self) {
93 self.entries.clear();
94 self.selected = None;
95 self.change_count += 1;
96 }
97}
98
99impl<V: Clone> Default for SelectorMap<V> {
100 fn default() -> Self {
101 Self::new()
102 }
103}
104
105pub fn new_selector_map<V: Clone>() -> SelectorMap<V> {
106 SelectorMap::new()
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn insert_and_get() {
115 let mut m: SelectorMap<i32> = new_selector_map();
116 m.insert("a", 1);
117 assert_eq!(m.get("a"), Some(&1));
118 }
119
120 #[test]
121 fn select_returns_value() {
122 let mut m: SelectorMap<i32> = new_selector_map();
123 m.insert("x", 42);
124 assert!(m.select("x"));
125 assert_eq!(m.selected_value(), Some(&42));
126 }
127
128 #[test]
129 fn select_nonexistent_fails() {
130 let mut m: SelectorMap<i32> = new_selector_map();
131 assert!(!m.select("missing"));
132 assert!(m.selected_key().is_none());
133 }
134
135 #[test]
136 fn deselect_clears() {
137 let mut m: SelectorMap<i32> = new_selector_map();
138 m.insert("a", 1);
139 m.select("a");
140 m.deselect();
141 assert!(m.selected_key().is_none());
142 }
143
144 #[test]
145 fn remove_clears_selection() {
146 let mut m: SelectorMap<i32> = new_selector_map();
147 m.insert("a", 5);
148 m.select("a");
149 m.remove("a");
150 assert!(m.selected_key().is_none());
151 }
152
153 #[test]
154 fn len_and_is_empty() {
155 let mut m: SelectorMap<u8> = new_selector_map();
156 assert!(m.is_empty());
157 m.insert("k", 1);
158 assert_eq!(m.len(), 1);
159 }
160
161 #[test]
162 fn change_count_increments() {
163 let mut m: SelectorMap<i32> = new_selector_map();
164 let before = m.change_count();
165 m.insert("a", 1);
166 assert!(m.change_count() > before);
167 }
168
169 #[test]
170 fn clear_removes_all() {
171 let mut m: SelectorMap<i32> = new_selector_map();
172 m.insert("a", 1);
173 m.select("a");
174 m.clear();
175 assert!(m.is_empty());
176 assert!(m.selected_key().is_none());
177 }
178
179 #[test]
180 fn keys_sorted() {
181 let mut m: SelectorMap<i32> = new_selector_map();
182 m.insert("b", 2);
183 m.insert("a", 1);
184 assert_eq!(m.keys(), vec!["a", "b"]);
185 }
186
187 #[test]
188 fn contains_check() {
189 let mut m: SelectorMap<i32> = new_selector_map();
190 m.insert("z", 9);
191 assert!(m.contains("z"));
192 assert!(!m.contains("nope"));
193 }
194}