1 use std::any::{Any, TypeId};
2 use std::collections::HashMap;
3 use std::sync::{Arc, RwLock};
4 use super::*;
5 pub struct Context {
6 data: Arc<RwLock<HashMap<TypeId, Box<dyn Any + Send + Sync >>>>,
7 named_data: Arc<RwLock<HashMap<(TypeId, String), Box<dyn Any + Send + Sync>>>>,
8 }
9
10 impl Context {
11 pub fn new() -> Self {
12 Self {
13 data: Arc::new(RwLock::new(HashMap::new())),
14 named_data: Arc::new(RwLock::new(HashMap::new())),
15 }
16 }
17
18 pub fn set<T: 'static + Clone + Send + Sync>(&self, value: T) {
19 let mut data = self.data.write().expect("Failed to acquire write lock");
20 data.insert(TypeId::of::<T>(), Box::new(value));
21 }
22
23 pub fn set_named<T: 'static + Clone + Send + Sync>(&self, name: &str, value: T) {
24 let mut data = self.named_data.write().expect("Failed to acquire write lock");
25 let key = (TypeId::of::<T>(), name.to_string());
26 data.insert(key, Box::new(value));
27 }
28
29 pub fn get<T: 'static + Clone + Send + Sync>(&self) -> Option<T> {
30 let data = self.data.read().expect("Failed to acquire read lock");
31 data.get(&TypeId::of::<T>())
32 .and_then(|boxed| boxed.downcast_ref::<T>())
33 .cloned()
34 }
35
36 pub fn get_named<T: 'static + Clone + Send + Sync>(&self, name: &str) -> Option<T> {
37 let data = self.named_data.read().expect("Failed to acquire read lock");
38 let key = (TypeId::of::<T>(), name.to_string());
39 data.get(&key)
40 .and_then(|boxed| boxed.downcast_ref::<T>())
41 .cloned()
42 }
43
44 pub fn update<T, F>(&self, f: F) -> crate::result::Result<()>
45 where
46 T: 'static + Clone + Send + Sync,
47 F: FnOnce(&mut T),
48 {
49 let mut data = self.data.write().expect("Failed to acquire write lock");
50
51 if let Some(value) = data.get_mut(&TypeId::of::<T>()) {
52 if let Some(value) = value.downcast_mut::<T>() {
53 f(value);
54 Ok(())
55 } else {
56 Err(format!("Type mismatch for {:?}", std::any::type_name::<T>()).into())
57 }
58 } else {
59 Err(format!("Type not found: {:?}", std::any::type_name::<T>()).into())
60 }
61 }
62
63 pub fn update_named<T, F>(&self, name: &str, f: F) -> crate::result::Result<()>
64 where
65 T: 'static + Clone + Send + Sync,
66 F: FnOnce(&mut T),
67 {
68 let mut data = self.named_data.write().expect("Failed to acquire write lock");
69 let key = (TypeId::of::<T>(), name.to_string());
70
71 if let Some(value) = data.get_mut(&key) {
72 if let Some(value) = value.downcast_mut::<T>() {
73 f(value);
74 Ok(())
75 } else {
76 Err(format!("Type mismatch for {:?}", std::any::type_name::<T>()).into())
77 }
78 } else {
79 Err(format!("Type not found: {:?}", std::any::type_name::<T>()).into())
80 }
81 }
82
83 pub fn remove<T: 'static>(&self) -> Option<Box<dyn Any + Send + Sync>> {
84 let mut data = self.data.write().expect("Failed to acquire write lock");
85 data.remove(&TypeId::of::<T>())
86 }
87
88 pub fn remove_named<T: 'static>(&self, name: &str) -> Option<Box<dyn Any + Send + Sync>> {
89 let mut data = self.named_data.write().expect("Failed to acquire write lock");
90 let key = (TypeId::of::<T>(), name.to_string());
91 data.remove(&key)
92 }
93
94 pub fn clear(&self) {
95 let mut data = self.data.write().expect("Failed to acquire write lock");
96 data.clear();
97 let mut named_data = self.named_data.write().expect("Failed to acquire write lock");
98 named_data.clear();
99 }
100
101 pub fn list(&self) {
102 showln!(yellow_bold, "context");
103 let data = self.data.read().expect("Failed to acquire read lock");
104 showln!(cyan_bold,"unnamed");
105 for (key, data) in data.iter() {
106
107 let data_type = std::any::type_name_of_val(&data);
108 showln!(gray_dim, format!("{:?}", key), yellow_bold, " → ", white_bold, format!("{:?}", data_type)) ;
109 }
110 let named_data = self.named_data.read().expect("Failed to acquire read lock");
111 showln!(cyan_bold,"named");
112 for (key, data) in named_data.iter() {
113 showln!(gray_dim, format!("{:?}", key), yellow_bold, " → ", white_bold, format!("{:?}", data));
114 }
115 }
116 }
117
118 use std::sync::OnceLock;
119
120 use crate::{cyan_bold, showln};
121
122 pub fn global_context() -> &'static Context {
123 static INSTANCE: OnceLock<Context> = OnceLock::new();
124 INSTANCE.get_or_init(Context::new)
125 }
126
127 #[macro_export]
128 macro_rules! set {
129 ($value:expr) => {
130 $crate::context::global_context().set($value)
131 };
132 ($name:ident => $value:expr) => {
133 $crate::context::global_context().set_named(stringify!($name), $value)
134 };
135 }
136
137 #[macro_export]
138 macro_rules! get {
139 ($type:ty) => {
140 $crate::context::global_context().get::<$type>().unwrap()
141 };
142 ($type:ty, $name:ident) => {
143 $crate::context::global_context().get_named::<$type>(stringify!($name)).unwrap()
144 };
145 }
146
147 #[macro_export]
148 macro_rules! maybe {
149 ($type:ty) => {
150 $crate::context::global_context().get::<$type>()
151 };
152 ($type:ty, $name:ident) => {
153 $crate::context::global_context().get_named::<$type>(stringify!($name))
154 };
155 }
156
157 #[macro_export]
158 macro_rules! update {
159 ($type:ty, $($field:ident : $value:expr),+ $(,)?) => {
160 $crate::context::global_context().update::<$type, _>(|value| {
161 $(value.$field = $value;)+
162 })
163 };
164 ($type:ty, $name:ident, $($field:ident : $value:expr),+ $(,)?) => {
165 $crate::context::global_context().update_named::<$type, _>(stringify!($name), |value| {
166 $(value.$field = $value;)+
167 })
168 };
169 ($type:ty, |$param:ident| $body:expr) => {
170 $crate::context::global_context().update::<$type, _>(|$param| $body)
171 };
172 ($type:ty, $name:ident, |$param:ident| $body:expr) => {
173 $crate::context::global_context().update_named::<$type, _>(stringify!($name), |$param| $body)
174 };
175 }
176
177 #[macro_export]
178 macro_rules! remove {
179 ($type:ty) => {
180 $crate::context::global_context().remove::<$type>()
181 };
182 ($type:ty, $name:ident) => {
183 $crate::context::global_context().remove_named::<$type>(stringify!($name))
184 };
185 }
186
187 #[macro_export]
188 macro_rules! get_or {
189 ($type:ty, $default:expr) => {
190 $crate::context::global_context().get::<$type>().unwrap_or_else(|| $default)
191 };
192 ($type:ty, $name:ident, $default:expr) => {
193 $crate::context::global_context().get_named::<$type>(stringify!($name)).unwrap_or_else(|| $default)
194 };
195 }
196
197 #[macro_export]
198 macro_rules! get_or_else {
199 ($type:ty, $default:expr) => {
200 $crate::context::global_context().get::<$type>().unwrap_or_else($default)
201 };
202 ($type:ty, $name:ident, $default:expr) => {
203 $crate::context::global_context().get_named::<$type>(stringify!($name)).unwrap_or_else($default)
204 };
205 }
206
207 #[macro_export]
208 macro_rules! get_or_insert {
209 ($type:ty, $default:expr) => {{
210 if let Some(value) = $crate::context::global_context().get::<$type>() {
211 value
212 } else {
213 let default = $default;
214 $crate::context::global_context().set(default.clone());
215 default
216 }
217 }};
218 ($type:ty, $name:ident, $default:expr) => {{
219 if let Some(value) = $crate::context::global_context().get_named::<$type>(stringify!($name)) {
220 value
221 } else {
222 let default = $default;
223 $crate::context::global_context().set_named(stringify!($name), default.clone());
224 default
225 }
226 }};
227 }
228
229 #[cfg(test)]
230 mod tests {
231 use super::*;
232
233 #[derive(Debug, Clone, PartialEq)]
234 struct User {
235 name: String,
236 age: u32,
237 }
238
239 #[test]
240 fn test_context() {
241 set!(42i32);
243 assert_eq!(get!(i32), 42);
244 assert_eq!(maybe!(i32), Some(42));
245
246 set!(name => "John".to_string());
248 assert_eq!(get!(String, name), "John".to_string());
249 assert_eq!(maybe!(String, name), Some("John".to_string()));
250
251 let user = User {
253 name: "Alice".to_string(),
254 age: 30,
255 };
256 set!(user.clone());
257 assert_eq!(get!(User), user);
258
259 assert_eq!(get!(User).name, "Alice");
261 assert_eq!(maybe!(User).map(|u| u.age), Some(30));
262
263 update!(User, name: "Bob".to_string()).unwrap();
265 update!(User, |u| u.age += 1).unwrap();
266
267 assert_eq!(
268 get!(User),
269 User {
270 name: "Bob".to_string(),
271 age: 31
272 }
273 );
274
275 set!(named_user => User { name: "Charlie".to_string(), age: 25 });
277 update!(User, named_user, age: 26).unwrap();
278 assert_eq!(get!(User, named_user).age, 26);
279
280 remove!(User);
282 assert_eq!(maybe!(User), None);
283
284 assert_eq!(get_or!(i32, 0), 42);
286 assert_eq!(get_or!(Vec<i32>, vec![1, 2, 3]), vec![1, 2, 3]);
287
288 assert_eq!(get_or_else!(i32, || 0), 42);
289 assert_eq!(get_or_else!(Vec<i32>, || vec![4, 5, 6]), vec![4, 5, 6]);
290
291 let inserted: Vec<i32> = get_or_insert!(Vec<i32>, vec![7, 8, 9]);
292 assert_eq!(inserted, vec![7, 8, 9]);
293 assert_eq!(get!(Vec<i32>), vec![7, 8, 9]);
294
295 assert_eq!(get_or!(String, other_name, "Default".to_string()), "Default".to_string());
297 assert_eq!(get_or_else!(String, other_name, || "Default".to_string()), "Default".to_string());
298 let inserted_named: String = get_or_insert!(String, new_name, "New".to_string());
299 assert_eq!(inserted_named, "New");
300 assert_eq!(get!(String, new_name), "New");
301
302 global_context().clear();
304 assert_eq!(maybe!(i32), None);
305 assert_eq!(maybe!(User), None);
306 assert_eq!(maybe!(Vec<i32>), None);
307 assert_eq!(maybe!(String, name), None);
308 }
309 }