singleton_registry/
macros.rs1#![allow(dead_code)]
2
3#[macro_export]
34macro_rules! define_registry {
35 ($name:ident) => {
36 pub mod $name {
37 use std::sync::{Arc, LazyLock, Mutex};
38 use std::collections::HashMap;
39 use std::any::{TypeId, Any};
40
41 static STORAGE: LazyLock<Mutex<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>> =
43 LazyLock::new(|| Mutex::new(HashMap::new()));
44
45 type TraceCallback = LazyLock<Mutex<Option<Arc<dyn Fn(&$crate::RegistryEvent) + Send + Sync>>>>;
48 static TRACE: TraceCallback = LazyLock::new(|| Mutex::new(None));
49
50 struct Api;
55
56 impl $crate::RegistryApi for Api {
57 fn storage() -> &'static LazyLock<Mutex<HashMap<TypeId, Arc<dyn Any + Send + Sync>>>> {
58 &STORAGE
59 }
60
61 fn trace() -> &'static TraceCallback {
62 &TRACE
63 }
64
65 }
68
69 const API: Api = Api;
71
72 pub fn register<T: Send + Sync + 'static>(value: T) {
76 use $crate::RegistryApi;
77 API.register(value)
78 }
79
80 pub fn register_arc<T: Send + Sync + 'static>(value: Arc<T>) {
82 use $crate::RegistryApi;
83 API.register_arc(value)
84 }
85
86 pub fn get<T: Send + Sync + 'static>() -> Result<Arc<T>, $crate::RegistryError> {
88 use $crate::RegistryApi;
89 API.get()
90 }
91
92 pub fn get_cloned<T: Send + Sync + Clone + 'static>() -> Result<T, $crate::RegistryError> {
94 use $crate::RegistryApi;
95 API.get_cloned()
96 }
97
98 pub fn try_get<T: Send + Sync + 'static>() -> Option<Arc<T>> {
100 use $crate::RegistryApi;
101 API.try_get()
102 }
103
104 pub fn contains<T: Send + Sync + 'static>() -> Result<bool, $crate::RegistryError> {
106 use $crate::RegistryApi;
107 API.contains::<T>()
108 }
109
110 pub fn set_trace_callback(callback: impl Fn(&$crate::RegistryEvent) + Send + Sync + 'static) {
112 use $crate::RegistryApi;
113 API.set_trace_callback(callback)
114 }
115
116 pub fn clear_trace_callback() {
118 use $crate::RegistryApi;
119 API.clear_trace_callback()
120 }
121
122 #[doc(hidden)]
124 pub fn clear() {
125 use $crate::RegistryApi;
126 API.clear()
127 }
128 }
129 };
130}
131
132#[cfg(test)]
133mod tests {
134 use std::sync::Arc;
136
137 #[test]
138 fn test_define_registry_macro() {
139 define_registry!(test_reg);
140
141 test_reg::register(100i32);
143 let value: Arc<i32> = test_reg::get().unwrap();
144 assert_eq!(*value, 100);
145
146 assert!(test_reg::contains::<i32>().unwrap());
148 assert!(!test_reg::contains::<f64>().unwrap());
149 }
150
151 #[test]
152 fn test_multiple_registries() {
153 define_registry!(reg_a);
154 define_registry!(reg_b);
155
156 reg_a::register(1i32);
158 reg_b::register(2i32);
159
160 let a_val: Arc<i32> = reg_a::get().unwrap();
162 let b_val: Arc<i32> = reg_b::get().unwrap();
163
164 assert_eq!(*a_val, 1);
165 assert_eq!(*b_val, 2);
166 }
167
168 #[test]
169 fn test_tracing() {
170 define_registry!(trace_test);
171
172 use std::sync::Mutex;
173 let events = Arc::new(Mutex::new(Vec::new()));
174 let events_clone = events.clone();
175
176 trace_test::set_trace_callback(move |event| {
177 events_clone.lock().unwrap().push(format!("{}", event));
178 });
179
180 trace_test::register(42i32);
181 let _: Arc<i32> = trace_test::get().unwrap();
182 let _ = trace_test::contains::<i32>();
183
184 let recorded = events.lock().unwrap();
185 assert_eq!(recorded.len(), 4);
186 assert!(recorded[0].contains("register"));
187 assert!(recorded[1].contains("register_completed"));
188 assert!(recorded[2].contains("get"));
189 assert!(recorded[3].contains("contains"));
190 }
191
192 #[test]
193 fn test_additional_functions() {
194 define_registry!(extra_test);
195
196 let val = Arc::new(99i32);
198 extra_test::register_arc(val);
199
200 let cloned: i32 = extra_test::get_cloned().unwrap();
202 assert_eq!(cloned, 99);
203
204 extra_test::set_trace_callback(|_| {});
206 extra_test::clear_trace_callback(); }
208
209 #[test]
210 fn test_try_get() {
211 define_registry!(try_get_test);
212
213 assert!(try_get_test::try_get::<i32>().is_none());
214 try_get_test::register(77i32);
215 let val = try_get_test::try_get::<i32>().expect("should be Some after register");
216 assert_eq!(*val, 77);
217 }
218}