oxur_repl/subprocess/
variable_store.rs1use std::any::Any;
9use std::collections::HashMap;
10use std::sync::Mutex;
11
12#[derive(Debug, Default)]
49pub struct VariableStore {
50 variables: HashMap<String, Box<dyn Any + Send>>,
52}
53
54impl VariableStore {
55 pub fn new() -> Self {
57 Self { variables: HashMap::new() }
58 }
59
60 pub fn set<T: 'static + Send>(&mut self, name: String, value: T) {
71 self.variables.insert(name, Box::new(value));
72 }
73
74 pub fn get<T: 'static>(&self, name: &str) -> Option<&T> {
87 self.variables.get(name).and_then(|boxed| boxed.downcast_ref::<T>())
88 }
89
90 pub fn get_mut<T: 'static>(&mut self, name: &str) -> Option<&mut T> {
103 self.variables.get_mut(name).and_then(|boxed| boxed.downcast_mut::<T>())
104 }
105
106 pub fn contains(&self, name: &str) -> bool {
108 self.variables.contains_key(name)
109 }
110
111 pub fn remove(&mut self, name: &str) -> bool {
115 self.variables.remove(name).is_some()
116 }
117
118 pub fn len(&self) -> usize {
120 self.variables.len()
121 }
122
123 pub fn is_empty(&self) -> bool {
125 self.variables.is_empty()
126 }
127
128 pub fn clear(&mut self) {
130 self.variables.clear();
131 }
132
133 pub fn names(&self) -> Vec<String> {
135 self.variables.keys().cloned().collect()
136 }
137}
138
139#[allow(dead_code)] static GLOBAL_STORE: Mutex<Option<VariableStore>> = Mutex::new(None);
145
146static GLOBAL_RESULT: Mutex<Option<String>> = Mutex::new(None);
151
152#[allow(dead_code)] pub fn init_global_store() {
157 let mut store = GLOBAL_STORE.lock().unwrap();
158 *store = Some(VariableStore::new());
159}
160
161#[allow(dead_code)] pub fn with_store<F, R>(f: F) -> R
191where
192 F: FnOnce(&mut VariableStore) -> R,
193{
194 let mut guard = GLOBAL_STORE.lock().unwrap();
195 let store =
196 guard.as_mut().expect("Global store not initialized - call init_global_store() first");
197 f(store)
198}
199
200pub fn set_result(value: String) {
215 let mut result = GLOBAL_RESULT.lock().unwrap();
216 *result = Some(value);
217}
218
219pub fn take_result() -> Option<String> {
228 let mut result = GLOBAL_RESULT.lock().unwrap();
229 result.take()
230}
231
232#[cfg(test)]
233mod tests {
234 use super::*;
235
236 #[test]
237 fn test_variable_store_basic() {
238 let mut store = VariableStore::new();
239
240 store.set("x".to_string(), 42i32);
241 assert_eq!(store.get::<i32>("x"), Some(&42));
242 }
243
244 #[test]
245 fn test_variable_store_type_mismatch() {
246 let mut store = VariableStore::new();
247
248 store.set("x".to_string(), 42i32);
249
250 assert_eq!(store.get::<String>("x"), None);
252 assert_eq!(store.get::<f64>("x"), None);
253 }
254
255 #[test]
256 fn test_variable_store_multiple_types() {
257 let mut store = VariableStore::new();
258
259 store.set("int_val".to_string(), 42i32);
260 store.set("str_val".to_string(), "hello".to_string());
261 store.set("bool_val".to_string(), true);
262
263 assert_eq!(store.get::<i32>("int_val"), Some(&42));
264 assert_eq!(store.get::<String>("str_val"), Some(&"hello".to_string()));
265 assert_eq!(store.get::<bool>("bool_val"), Some(&true));
266 }
267
268 #[test]
269 fn test_variable_store_overwrite() {
270 let mut store = VariableStore::new();
271
272 store.set("x".to_string(), 42i32);
273 assert_eq!(store.get::<i32>("x"), Some(&42));
274
275 store.set("x".to_string(), 100i32);
276 assert_eq!(store.get::<i32>("x"), Some(&100));
277 }
278
279 #[test]
280 fn test_variable_store_overwrite_different_type() {
281 let mut store = VariableStore::new();
282
283 store.set("x".to_string(), 42i32);
284 assert_eq!(store.get::<i32>("x"), Some(&42));
285
286 store.set("x".to_string(), "hello".to_string());
288 assert_eq!(store.get::<String>("x"), Some(&"hello".to_string()));
289 assert_eq!(store.get::<i32>("x"), None); }
291
292 #[test]
293 fn test_variable_store_get_mut() {
294 let mut store = VariableStore::new();
295
296 store.set("x".to_string(), 42i32);
297
298 if let Some(x) = store.get_mut::<i32>("x") {
299 *x += 10;
300 }
301
302 assert_eq!(store.get::<i32>("x"), Some(&52));
303 }
304
305 #[test]
306 fn test_variable_store_contains() {
307 let mut store = VariableStore::new();
308
309 store.set("x".to_string(), 42i32);
310
311 assert!(store.contains("x"));
312 assert!(!store.contains("y"));
313 }
314
315 #[test]
316 fn test_variable_store_remove() {
317 let mut store = VariableStore::new();
318
319 store.set("x".to_string(), 42i32);
320 assert!(store.contains("x"));
321
322 assert!(store.remove("x"));
323 assert!(!store.contains("x"));
324 assert!(!store.remove("x")); }
326
327 #[test]
328 fn test_variable_store_len() {
329 let mut store = VariableStore::new();
330
331 assert_eq!(store.len(), 0);
332 assert!(store.is_empty());
333
334 store.set("x".to_string(), 42i32);
335 assert_eq!(store.len(), 1);
336 assert!(!store.is_empty());
337
338 store.set("y".to_string(), "hello".to_string());
339 assert_eq!(store.len(), 2);
340 }
341
342 #[test]
343 fn test_variable_store_clear() {
344 let mut store = VariableStore::new();
345
346 store.set("x".to_string(), 42i32);
347 store.set("y".to_string(), "hello".to_string());
348 assert_eq!(store.len(), 2);
349
350 store.clear();
351 assert_eq!(store.len(), 0);
352 assert!(store.is_empty());
353 }
354
355 #[test]
356 fn test_variable_store_names() {
357 let mut store = VariableStore::new();
358
359 store.set("x".to_string(), 42i32);
360 store.set("y".to_string(), "hello".to_string());
361 store.set("z".to_string(), true);
362
363 let names = store.names();
364 assert_eq!(names.len(), 3);
365 assert!(names.contains(&"x".to_string()));
366 assert!(names.contains(&"y".to_string()));
367 assert!(names.contains(&"z".to_string()));
368 }
369
370 #[test]
371 fn test_variable_store_complex_types() {
372 let mut store = VariableStore::new();
373
374 store.set("vec".to_string(), vec![1, 2, 3]);
376 assert_eq!(store.get::<Vec<i32>>("vec"), Some(&vec![1, 2, 3]));
377
378 #[derive(Debug, PartialEq)]
380 struct Point {
381 x: i32,
382 y: i32,
383 }
384
385 store.set("point".to_string(), Point { x: 10, y: 20 });
386 assert_eq!(store.get::<Point>("point"), Some(&Point { x: 10, y: 20 }));
387 }
388
389 #[test]
390 fn test_global_store() {
391 init_global_store();
392
393 with_store(|store| {
395 store.set("global_x".to_string(), 42i32);
396 });
397
398 let result = with_store(|store| store.get::<i32>("global_x").copied());
400
401 assert_eq!(result, Some(42));
402
403 with_store(|store| store.clear());
405 }
406
407 #[test]
408 fn test_global_store_multiple_accesses() {
409 init_global_store();
410
411 with_store(|store| store.clear());
412
413 with_store(|store| {
415 store.set("a".to_string(), 1i32);
416 });
417
418 with_store(|store| {
419 store.set("b".to_string(), 2i32);
420 });
421
422 let sum = with_store(|store| {
423 let a = store.get::<i32>("a").copied().unwrap_or(0);
424 let b = store.get::<i32>("b").copied().unwrap_or(0);
425 a + b
426 });
427
428 assert_eq!(sum, 3);
429 }
430}