sovran_typemap/store_value.rs
1// src/store_value.rs
2use std::any::{Any, TypeId};
3use std::collections::HashMap;
4
5/// A trait that combines Any + Clone for value-based storage.
6pub trait CloneAny: Any + Send + Sync {
7 /// Clone this value into a boxed trait object.
8 fn clone_any(&self) -> Box<dyn CloneAny>;
9 /// Get a reference to the underlying Any.
10 fn as_any(&self) -> &dyn Any;
11 /// Get a mutable reference to the underlying Any.
12 fn as_any_mut(&mut self) -> &mut dyn Any;
13}
14
15impl<T: Clone + Any + Send + Sync> CloneAny for T {
16 fn clone_any(&self) -> Box<dyn CloneAny> {
17 Box::new(self.clone())
18 }
19
20 fn as_any(&self) -> &dyn Any {
21 self
22 }
23
24 fn as_any_mut(&mut self) -> &mut dyn Any {
25 self
26 }
27}
28
29// Implement Clone for Box<dyn CloneAny> - this is the key trick
30// NOTE: Must use (**self) to call the inner type's clone_any, not the Box's
31impl Clone for Box<dyn CloneAny> {
32 fn clone(&self) -> Self {
33 (**self).clone_any()
34 }
35}
36
37/// A cloneable, value-based container that stores exactly one value per type.
38///
39/// Unlike `TypeStore`, `TypeStoreValue` does not use `Arc<Mutex<>>` internally,
40/// making it cloneable and suitable for single-threaded contexts or when you
41/// need to snapshot state.
42///
43/// # Examples
44///
45/// ```
46/// use sovran_typemap::TypeStoreValue;
47///
48/// #[derive(Clone, Debug, PartialEq)]
49/// struct Config {
50/// debug: bool,
51/// max_retries: u32,
52/// }
53///
54/// let mut store = TypeStoreValue::new();
55///
56/// store.set(Config { debug: true, max_retries: 3 });
57/// store.set(42i32);
58///
59/// // Clone the entire store
60/// let snapshot = store.clone();
61///
62/// // Modify original
63/// store.with_mut::<Config, _, _>(|cfg| {
64/// cfg.debug = false;
65/// });
66///
67/// // Snapshot is unchanged
68/// assert_eq!(snapshot.get::<Config>().unwrap().debug, true);
69/// assert_eq!(store.get::<Config>().unwrap().debug, false);
70/// ```
71#[derive(Default, Clone)]
72pub struct TypeStoreValue {
73 items: HashMap<TypeId, Box<dyn CloneAny>>,
74}
75
76impl std::fmt::Debug for TypeStoreValue {
77 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
78 f.debug_struct("TypeStoreValue")
79 .field("len", &self.items.len())
80 .finish()
81 }
82}
83
84impl TypeStoreValue {
85 /// Creates a new, empty TypeStoreValue.
86 ///
87 /// # Examples
88 ///
89 /// ```
90 /// use sovran_typemap::TypeStoreValue;
91 ///
92 /// let store = TypeStoreValue::new();
93 /// assert!(store.is_empty());
94 /// ```
95 pub fn new() -> Self {
96 Self {
97 items: HashMap::new(),
98 }
99 }
100
101 /// Stores a value, using its type as the key.
102 ///
103 /// If a value of this type already exists, it will be replaced.
104 ///
105 /// # Examples
106 ///
107 /// ```
108 /// use sovran_typemap::TypeStoreValue;
109 ///
110 /// let mut store = TypeStoreValue::new();
111 ///
112 /// store.set(42i32);
113 /// store.set("hello".to_string());
114 ///
115 /// // Overwrites the previous i32
116 /// store.set(100i32);
117 /// assert_eq!(store.get::<i32>(), Some(100));
118 /// ```
119 pub fn set<V>(&mut self, value: V)
120 where
121 V: Clone + Any + Send + Sync,
122 {
123 self.items.insert(TypeId::of::<V>(), Box::new(value));
124 }
125
126 /// Stores a value generated by a closure.
127 ///
128 /// # Examples
129 ///
130 /// ```
131 /// use sovran_typemap::TypeStoreValue;
132 ///
133 /// let mut store = TypeStoreValue::new();
134 ///
135 /// store.set_with(|| vec![1, 2, 3, 4, 5]);
136 ///
137 /// assert_eq!(store.get::<Vec<i32>>(), Some(vec![1, 2, 3, 4, 5]));
138 /// ```
139 pub fn set_with<V, F>(&mut self, f: F)
140 where
141 V: Clone + Any + Send + Sync,
142 F: FnOnce() -> V,
143 {
144 self.set(f());
145 }
146
147 /// Retrieves a clone of a value by its type.
148 ///
149 /// Returns `None` if no value of this type exists.
150 ///
151 /// # Examples
152 ///
153 /// ```
154 /// use sovran_typemap::TypeStoreValue;
155 ///
156 /// let mut store = TypeStoreValue::new();
157 /// store.set(42i32);
158 ///
159 /// assert_eq!(store.get::<i32>(), Some(42));
160 /// assert_eq!(store.get::<String>(), None);
161 /// ```
162 pub fn get<V>(&self) -> Option<V>
163 where
164 V: Clone + Any + Send + Sync,
165 {
166 self.with(|v: &V| v.clone())
167 }
168
169 /// Accesses a value by type with a read-only closure.
170 ///
171 /// Returns `None` if no value of this type exists.
172 ///
173 /// # Examples
174 ///
175 /// ```
176 /// use sovran_typemap::TypeStoreValue;
177 ///
178 /// let mut store = TypeStoreValue::new();
179 /// store.set(vec![1, 2, 3, 4, 5]);
180 ///
181 /// let sum = store.with::<Vec<i32>, _, _>(|numbers| {
182 /// numbers.iter().sum::<i32>()
183 /// });
184 /// assert_eq!(sum, Some(15));
185 /// ```
186 pub fn with<V, F, R>(&self, f: F) -> Option<R>
187 where
188 V: Any,
189 F: FnOnce(&V) -> R,
190 {
191 self.items
192 .get(&TypeId::of::<V>())
193 .and_then(|boxed| (**boxed).as_any().downcast_ref::<V>())
194 .map(f)
195 }
196
197 /// Accesses a value by type with a read-write closure.
198 ///
199 /// Returns `None` if no value of this type exists.
200 ///
201 /// # Examples
202 ///
203 /// ```
204 /// use sovran_typemap::TypeStoreValue;
205 ///
206 /// let mut store = TypeStoreValue::new();
207 /// store.set(vec![1, 2, 3]);
208 ///
209 /// store.with_mut::<Vec<i32>, _, _>(|numbers| {
210 /// numbers.push(4);
211 /// numbers.push(5);
212 /// });
213 ///
214 /// assert_eq!(store.get::<Vec<i32>>(), Some(vec![1, 2, 3, 4, 5]));
215 /// ```
216 pub fn with_mut<V, F, R>(&mut self, f: F) -> Option<R>
217 where
218 V: Any,
219 F: FnOnce(&mut V) -> R,
220 {
221 self.items
222 .get_mut(&TypeId::of::<V>())
223 .and_then(|boxed| (**boxed).as_any_mut().downcast_mut::<V>())
224 .map(f)
225 }
226
227 /// Removes a value by its type.
228 ///
229 /// Returns `true` if a value was removed, `false` if no value of that type existed.
230 ///
231 /// # Examples
232 ///
233 /// ```
234 /// use sovran_typemap::TypeStoreValue;
235 ///
236 /// let mut store = TypeStoreValue::new();
237 /// store.set(42i32);
238 ///
239 /// assert!(store.remove::<i32>());
240 /// assert!(!store.remove::<i32>()); // Already removed
241 /// ```
242 pub fn remove<V: Any>(&mut self) -> bool {
243 self.items.remove(&TypeId::of::<V>()).is_some()
244 }
245
246 /// Checks if a value of the given type exists.
247 ///
248 /// # Examples
249 ///
250 /// ```
251 /// use sovran_typemap::TypeStoreValue;
252 ///
253 /// let mut store = TypeStoreValue::new();
254 ///
255 /// assert!(!store.contains::<i32>());
256 /// store.set(42i32);
257 /// assert!(store.contains::<i32>());
258 /// ```
259 pub fn contains<V: Any>(&self) -> bool {
260 self.items.contains_key(&TypeId::of::<V>())
261 }
262
263 /// Gets the number of values in the store.
264 ///
265 /// # Examples
266 ///
267 /// ```
268 /// use sovran_typemap::TypeStoreValue;
269 ///
270 /// let mut store = TypeStoreValue::new();
271 /// assert_eq!(store.len(), 0);
272 ///
273 /// store.set(42i32);
274 /// store.set("hello".to_string());
275 /// assert_eq!(store.len(), 2);
276 /// ```
277 pub fn len(&self) -> usize {
278 self.items.len()
279 }
280
281 /// Checks if the store is empty.
282 ///
283 /// # Examples
284 ///
285 /// ```
286 /// use sovran_typemap::TypeStoreValue;
287 ///
288 /// let mut store = TypeStoreValue::new();
289 /// assert!(store.is_empty());
290 ///
291 /// store.set(42i32);
292 /// assert!(!store.is_empty());
293 /// ```
294 pub fn is_empty(&self) -> bool {
295 self.items.is_empty()
296 }
297}
298
299#[cfg(test)]
300mod tests {
301 use super::*;
302
303 #[derive(Clone, Debug, PartialEq)]
304 struct TestConfig {
305 name: String,
306 value: i32,
307 }
308
309 #[derive(Clone, Debug, PartialEq)]
310 struct AnotherConfig {
311 enabled: bool,
312 }
313
314 #[test]
315 fn test_set_and_get() {
316 let mut store = TypeStoreValue::new();
317
318 store.set(TestConfig {
319 name: "test".to_string(),
320 value: 42,
321 });
322
323 let config = store.get::<TestConfig>().unwrap();
324 assert_eq!(config.name, "test");
325 assert_eq!(config.value, 42);
326 }
327
328 #[test]
329 fn test_multiple_types() {
330 let mut store = TypeStoreValue::new();
331
332 store.set(TestConfig {
333 name: "test".to_string(),
334 value: 42,
335 });
336 store.set(AnotherConfig { enabled: true });
337 store.set(123i32);
338 store.set("hello".to_string());
339
340 assert_eq!(store.get::<TestConfig>().unwrap().value, 42);
341 assert!(store.get::<AnotherConfig>().unwrap().enabled);
342 assert_eq!(store.get::<i32>().unwrap(), 123);
343 assert_eq!(store.get::<String>().unwrap(), "hello");
344 }
345
346 #[test]
347 fn test_overwrite() {
348 let mut store = TypeStoreValue::new();
349
350 store.set(42i32);
351 assert_eq!(store.get::<i32>(), Some(42));
352
353 store.set(100i32);
354 assert_eq!(store.get::<i32>(), Some(100));
355
356 // Still only one item
357 assert_eq!(store.len(), 1);
358 }
359
360 #[test]
361 fn test_clone() {
362 let mut store = TypeStoreValue::new();
363 store.set(TestConfig {
364 name: "original".to_string(),
365 value: 42,
366 });
367 store.set(100i32);
368
369 // Clone the store
370 let snapshot = store.clone();
371
372 // Modify original
373 store.with_mut::<TestConfig, _, _>(|cfg| {
374 cfg.name = "modified".to_string();
375 cfg.value = 99;
376 });
377 store.set(200i32);
378
379 // Snapshot should be unchanged
380 assert_eq!(snapshot.get::<TestConfig>().unwrap().name, "original");
381 assert_eq!(snapshot.get::<TestConfig>().unwrap().value, 42);
382 assert_eq!(snapshot.get::<i32>(), Some(100));
383
384 // Original should be modified
385 assert_eq!(store.get::<TestConfig>().unwrap().name, "modified");
386 assert_eq!(store.get::<TestConfig>().unwrap().value, 99);
387 assert_eq!(store.get::<i32>(), Some(200));
388 }
389
390 #[test]
391 fn test_with() {
392 let mut store = TypeStoreValue::new();
393 store.set(vec![1, 2, 3, 4, 5]);
394
395 let sum = store.with::<Vec<i32>, _, _>(|v| v.iter().sum::<i32>());
396 assert_eq!(sum, Some(15));
397
398 // Non-existent type
399 let result = store.with::<String, _, _>(|s| s.len());
400 assert_eq!(result, None);
401 }
402
403 #[test]
404 fn test_with_mut() {
405 let mut store = TypeStoreValue::new();
406 store.set(vec![1, 2, 3]);
407
408 store.with_mut::<Vec<i32>, _, _>(|v| {
409 v.push(4);
410 v.push(5);
411 });
412
413 assert_eq!(store.get::<Vec<i32>>(), Some(vec![1, 2, 3, 4, 5]));
414 }
415
416 #[test]
417 fn test_remove() {
418 let mut store = TypeStoreValue::new();
419 store.set(42i32);
420
421 assert!(store.contains::<i32>());
422 assert!(store.remove::<i32>());
423 assert!(!store.contains::<i32>());
424 assert!(!store.remove::<i32>());
425 }
426
427 #[test]
428 fn test_contains() {
429 let mut store = TypeStoreValue::new();
430
431 assert!(!store.contains::<i32>());
432 store.set(42i32);
433 assert!(store.contains::<i32>());
434 }
435
436 #[test]
437 fn test_len_and_is_empty() {
438 let mut store = TypeStoreValue::new();
439
440 assert!(store.is_empty());
441 assert_eq!(store.len(), 0);
442
443 store.set(42i32);
444 assert!(!store.is_empty());
445 assert_eq!(store.len(), 1);
446
447 store.set("hello".to_string());
448 assert_eq!(store.len(), 2);
449
450 store.remove::<i32>();
451 assert_eq!(store.len(), 1);
452 }
453
454 #[test]
455 fn test_set_with() {
456 let mut store = TypeStoreValue::new();
457
458 store.set_with(|| TestConfig {
459 name: "lazy".to_string(),
460 value: 99,
461 });
462
463 let config = store.get::<TestConfig>().unwrap();
464 assert_eq!(config.name, "lazy");
465 assert_eq!(config.value, 99);
466 }
467
468 #[test]
469 fn test_not_found_returns_none() {
470 let store = TypeStoreValue::new();
471
472 assert_eq!(store.get::<TestConfig>(), None);
473 assert_eq!(store.with::<i32, _, _>(|v| *v), None);
474 }
475
476 #[test]
477 fn test_debug() {
478 let mut store = TypeStoreValue::new();
479 store.set(42i32);
480 store.set("hello".to_string());
481
482 let debug_str = format!("{:?}", store);
483 assert!(debug_str.contains("TypeStoreValue"));
484 assert!(debug_str.contains("len"));
485 assert!(debug_str.contains("2"));
486 }
487}