oxihuman_core/
context_map.rs1#![allow(dead_code)]
4
5use std::collections::HashMap;
8
9#[allow(dead_code)]
11#[derive(Debug, Clone, PartialEq)]
12pub enum CtxValue {
13 Bool(bool),
14 Int(i64),
15 Float(f32),
16 Str(String),
17 Bytes(Vec<u8>),
18}
19
20#[allow(dead_code)]
22#[derive(Debug, Clone, Default)]
23pub struct ContextMap {
24 data: HashMap<String, CtxValue>,
25}
26
27#[allow(dead_code)]
28impl ContextMap {
29 pub fn new() -> Self {
30 Self::default()
31 }
32
33 pub fn set_bool(&mut self, key: &str, val: bool) {
34 self.data.insert(key.to_string(), CtxValue::Bool(val));
35 }
36
37 pub fn set_int(&mut self, key: &str, val: i64) {
38 self.data.insert(key.to_string(), CtxValue::Int(val));
39 }
40
41 pub fn set_float(&mut self, key: &str, val: f32) {
42 self.data.insert(key.to_string(), CtxValue::Float(val));
43 }
44
45 pub fn set_str(&mut self, key: &str, val: &str) {
46 self.data
47 .insert(key.to_string(), CtxValue::Str(val.to_string()));
48 }
49
50 pub fn set_bytes(&mut self, key: &str, val: Vec<u8>) {
51 self.data.insert(key.to_string(), CtxValue::Bytes(val));
52 }
53
54 pub fn get(&self, key: &str) -> Option<&CtxValue> {
55 self.data.get(key)
56 }
57
58 pub fn get_bool(&self, key: &str) -> Option<bool> {
59 match self.data.get(key) {
60 Some(CtxValue::Bool(v)) => Some(*v),
61 _ => None,
62 }
63 }
64
65 pub fn get_int(&self, key: &str) -> Option<i64> {
66 match self.data.get(key) {
67 Some(CtxValue::Int(v)) => Some(*v),
68 _ => None,
69 }
70 }
71
72 pub fn get_float(&self, key: &str) -> Option<f32> {
73 match self.data.get(key) {
74 Some(CtxValue::Float(v)) => Some(*v),
75 _ => None,
76 }
77 }
78
79 pub fn get_str(&self, key: &str) -> Option<&str> {
80 match self.data.get(key) {
81 Some(CtxValue::Str(v)) => Some(v.as_str()),
82 _ => None,
83 }
84 }
85
86 pub fn contains(&self, key: &str) -> bool {
87 self.data.contains_key(key)
88 }
89
90 pub fn remove(&mut self, key: &str) -> bool {
91 self.data.remove(key).is_some()
92 }
93
94 pub fn len(&self) -> usize {
95 self.data.len()
96 }
97
98 pub fn is_empty(&self) -> bool {
99 self.data.is_empty()
100 }
101
102 pub fn keys(&self) -> Vec<&str> {
103 self.data.keys().map(|k| k.as_str()).collect()
104 }
105
106 pub fn clear(&mut self) {
107 self.data.clear();
108 }
109
110 pub fn merge(&mut self, other: &ContextMap) {
112 for (k, v) in &other.data {
113 self.data.insert(k.clone(), v.clone());
114 }
115 }
116}
117
118#[cfg(test)]
119mod tests {
120 use super::*;
121
122 #[test]
123 fn new_is_empty() {
124 assert!(ContextMap::new().is_empty());
125 }
126
127 #[test]
128 fn set_get_bool() {
129 let mut m = ContextMap::new();
130 m.set_bool("flag", true);
131 assert_eq!(m.get_bool("flag"), Some(true));
132 }
133
134 #[test]
135 fn set_get_int() {
136 let mut m = ContextMap::new();
137 m.set_int("count", 42);
138 assert_eq!(m.get_int("count"), Some(42));
139 }
140
141 #[test]
142 fn set_get_float() {
143 let mut m = ContextMap::new();
144 m.set_float("ratio", std::f32::consts::PI);
145 assert!(
146 (m.get_float("ratio").expect("should succeed") - std::f32::consts::PI).abs() < 1e-6
147 );
148 }
149
150 #[test]
151 fn set_get_str() {
152 let mut m = ContextMap::new();
153 m.set_str("label", "hello");
154 assert_eq!(m.get_str("label"), Some("hello"));
155 }
156
157 #[test]
158 fn type_mismatch_returns_none() {
159 let mut m = ContextMap::new();
160 m.set_bool("x", false);
161 assert!(m.get_int("x").is_none());
162 }
163
164 #[test]
165 fn remove_entry() {
166 let mut m = ContextMap::new();
167 m.set_str("a", "v");
168 assert!(m.remove("a"));
169 assert!(!m.contains("a"));
170 assert!(!m.remove("a"));
171 }
172
173 #[test]
174 fn merge_overwrites() {
175 let mut a = ContextMap::new();
176 a.set_int("n", 1);
177 let mut b = ContextMap::new();
178 b.set_int("n", 2);
179 b.set_str("extra", "hi");
180 a.merge(&b);
181 assert_eq!(a.get_int("n"), Some(2));
182 assert_eq!(a.get_str("extra"), Some("hi"));
183 }
184
185 #[test]
186 fn set_bytes_and_get() {
187 let mut m = ContextMap::new();
188 m.set_bytes("data", vec![1, 2, 3]);
189 assert!(m
190 .get("data")
191 .is_some_and(|v| matches!(v, CtxValue::Bytes(_))));
192 }
193
194 #[test]
195 fn clear_empties() {
196 let mut m = ContextMap::new();
197 m.set_int("a", 1);
198 m.clear();
199 assert!(m.is_empty());
200 }
201}