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}