oxihuman_core/
chain_map.rs1#![allow(dead_code)]
4
5use std::collections::HashMap;
6
7#[allow(dead_code)]
9#[derive(Debug, Clone)]
10pub struct ChainMap {
11 layers: Vec<HashMap<String, String>>,
12}
13
14impl Default for ChainMap {
15 fn default() -> Self {
16 Self::new()
17 }
18}
19
20#[allow(dead_code)]
21impl ChainMap {
22 pub fn new() -> Self {
23 Self {
24 layers: vec![HashMap::new()],
25 }
26 }
27
28 pub fn push_layer(&mut self) {
29 self.layers.push(HashMap::new());
30 }
31
32 pub fn pop_layer(&mut self) -> bool {
33 if self.layers.len() > 1 {
34 self.layers.pop();
35 true
36 } else {
37 false
38 }
39 }
40
41 pub fn layer_count(&self) -> usize {
42 self.layers.len()
43 }
44
45 pub fn set(&mut self, key: &str, value: &str) {
46 if let Some(top) = self.layers.last_mut() {
47 top.insert(key.to_string(), value.to_string());
48 }
49 }
50
51 pub fn get(&self, key: &str) -> Option<&str> {
52 for layer in self.layers.iter().rev() {
53 if let Some(v) = layer.get(key) {
54 return Some(v.as_str());
55 }
56 }
57 None
58 }
59
60 pub fn contains_key(&self, key: &str) -> bool {
61 self.get(key).is_some()
62 }
63
64 pub fn remove_from_top(&mut self, key: &str) -> bool {
65 self.layers
66 .last_mut()
67 .is_some_and(|top| top.remove(key).is_some())
68 }
69
70 pub fn top_layer_count(&self) -> usize {
71 self.layers.last().map_or(0, |l| l.len())
72 }
73
74 pub fn total_entries(&self) -> usize {
75 self.layers.iter().map(|l| l.len()).sum()
76 }
77
78 pub fn all_keys(&self) -> Vec<String> {
79 let mut keys: Vec<String> = self.layers.iter().flat_map(|l| l.keys().cloned()).collect();
80 keys.sort();
81 keys.dedup();
82 keys
83 }
84
85 pub fn flatten(&self) -> HashMap<String, String> {
86 let mut result = HashMap::new();
87 for layer in &self.layers {
88 for (k, v) in layer {
89 result.insert(k.clone(), v.clone());
90 }
91 }
92 result
93 }
94
95 pub fn clear_top(&mut self) {
96 if let Some(top) = self.layers.last_mut() {
97 top.clear();
98 }
99 }
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn test_new() {
108 let cm = ChainMap::new();
109 assert_eq!(cm.layer_count(), 1);
110 }
111
112 #[test]
113 fn test_set_and_get() {
114 let mut cm = ChainMap::new();
115 cm.set("k", "v");
116 assert_eq!(cm.get("k"), Some("v"));
117 }
118
119 #[test]
120 fn test_layer_override() {
121 let mut cm = ChainMap::new();
122 cm.set("k", "base");
123 cm.push_layer();
124 cm.set("k", "override");
125 assert_eq!(cm.get("k"), Some("override"));
126 }
127
128 #[test]
129 fn test_fallthrough() {
130 let mut cm = ChainMap::new();
131 cm.set("k", "base");
132 cm.push_layer();
133 assert_eq!(cm.get("k"), Some("base"));
134 }
135
136 #[test]
137 fn test_pop_layer() {
138 let mut cm = ChainMap::new();
139 cm.set("k", "base");
140 cm.push_layer();
141 cm.set("k", "top");
142 assert!(cm.pop_layer());
143 assert_eq!(cm.get("k"), Some("base"));
144 }
145
146 #[test]
147 fn test_cannot_pop_last() {
148 let mut cm = ChainMap::new();
149 assert!(!cm.pop_layer());
150 }
151
152 #[test]
153 fn test_contains_key() {
154 let mut cm = ChainMap::new();
155 assert!(!cm.contains_key("x"));
156 cm.set("x", "y");
157 assert!(cm.contains_key("x"));
158 }
159
160 #[test]
161 fn test_all_keys() {
162 let mut cm = ChainMap::new();
163 cm.set("b", "1");
164 cm.push_layer();
165 cm.set("a", "2");
166 let keys = cm.all_keys();
167 assert_eq!(keys, vec!["a", "b"]);
168 }
169
170 #[test]
171 fn test_flatten() {
172 let mut cm = ChainMap::new();
173 cm.set("a", "1");
174 cm.push_layer();
175 cm.set("a", "2");
176 cm.set("b", "3");
177 let flat = cm.flatten();
178 assert_eq!(flat["a"], "2");
179 assert_eq!(flat["b"], "3");
180 }
181
182 #[test]
183 fn test_remove_from_top() {
184 let mut cm = ChainMap::new();
185 cm.set("a", "1");
186 cm.push_layer();
187 cm.set("a", "2");
188 assert!(cm.remove_from_top("a"));
189 assert_eq!(cm.get("a"), Some("1"));
190 }
191}