spawned_concurrency/
registry.rs1use std::any::Any;
2use std::collections::HashMap;
3use std::sync::{OnceLock, RwLock};
4
5type Store = RwLock<HashMap<String, Box<dyn Any + Send + Sync>>>;
6
7fn global_store() -> &'static Store {
8 static STORE: OnceLock<Store> = OnceLock::new();
9 STORE.get_or_init(|| RwLock::new(HashMap::new()))
10}
11
12#[derive(Debug, thiserror::Error)]
14pub enum RegistryError {
15 #[error("name '{0}' is already registered")]
17 AlreadyRegistered(String),
18}
19
20pub fn register<T: Clone + Send + Sync + 'static>(
25 name: &str,
26 value: T,
27) -> Result<(), RegistryError> {
28 use std::collections::hash_map::Entry;
29 let mut store = global_store().write().unwrap_or_else(|p| p.into_inner());
30 match store.entry(name.to_string()) {
31 Entry::Occupied(e) => Err(RegistryError::AlreadyRegistered(e.key().clone())),
32 Entry::Vacant(e) => {
33 e.insert(Box::new(value));
34 Ok(())
35 }
36 }
37}
38
39pub fn whereis<T: Clone + Send + Sync + 'static>(name: &str) -> Option<T> {
42 let store = global_store().read().unwrap_or_else(|p| p.into_inner());
43 store.get(name)?.downcast_ref::<T>().cloned()
44}
45
46pub fn unregister(name: &str) {
48 let mut store = global_store().write().unwrap_or_else(|p| p.into_inner());
49 store.remove(name);
50}
51
52pub fn registered() -> Vec<String> {
54 let store = global_store().read().unwrap_or_else(|p| p.into_inner());
55 store.keys().cloned().collect()
56}
57
58#[cfg(test)]
59mod tests {
60 use super::*;
61
62 #[test]
65 fn register_and_whereis() {
66 register("test_rw_1", 42u64).unwrap();
67 let val: Option<u64> = whereis("test_rw_1");
68 assert_eq!(val, Some(42));
69 }
70
71 #[test]
72 fn whereis_wrong_type_returns_none() {
73 register("test_wt_1", 42u64).unwrap();
74 let val: Option<String> = whereis("test_wt_1");
75 assert_eq!(val, None);
76 }
77
78 #[test]
79 fn whereis_missing_returns_none() {
80 let val: Option<u64> = whereis("nonexistent_key");
81 assert_eq!(val, None);
82 }
83
84 #[test]
85 fn duplicate_register_fails() {
86 register("test_dup_1", 1u32).unwrap();
87 let result = register("test_dup_1", 2u32);
88 assert!(result.is_err());
89 }
90
91 #[test]
92 fn unregister_removes_entry() {
93 register("test_unreg_1", "hello".to_string()).unwrap();
94 unregister("test_unreg_1");
95 let val: Option<String> = whereis("test_unreg_1");
96 assert_eq!(val, None);
97 }
98
99 #[test]
100 fn registered_lists_names() {
101 register("test_list_a", 1u32).unwrap();
102 register("test_list_b", 2u32).unwrap();
103 let names = registered();
104 assert!(names.contains(&"test_list_a".to_string()));
105 assert!(names.contains(&"test_list_b".to_string()));
106 }
107}