sovran_typemap/
store.rs

1// src/store.rs
2use std::any::{type_name, Any, TypeId};
3use std::collections::HashMap;
4use std::sync::{Arc, Mutex};
5
6use crate::any_value::AnyValue;
7use crate::error::MapError;
8
9/// A thread-safe container that stores exactly one value per type.
10///
11/// `TypeStore` provides a simple way to store and retrieve values using their
12/// type as the key. This is useful for dependency injection, service locators,
13/// and managing application-wide state without explicit key management.
14///
15/// Unlike `TypeMap` which uses explicit keys, `TypeStore` uses the type itself
16/// as the key, meaning you can only store one value of each type.
17///
18/// # Examples
19///
20/// ```
21/// use sovran_typemap::{TypeStore, MapError};
22///
23/// #[derive(Clone, Debug)]
24/// struct DatabaseConfig {
25///     host: String,
26///     port: u16,
27/// }
28///
29/// #[derive(Clone, Debug)]
30/// struct AppConfig {
31///     name: String,
32///     debug: bool,
33/// }
34///
35/// fn main() -> Result<(), MapError> {
36///     let store = TypeStore::new();
37///
38///     // Store configurations by type
39///     store.set(DatabaseConfig {
40///         host: "localhost".to_string(),
41///         port: 5432,
42///     })?;
43///
44///     store.set(AppConfig {
45///         name: "MyApp".to_string(),
46///         debug: true,
47///     })?;
48///
49///     // Retrieve by type - no key needed
50///     let db_config = store.get::<DatabaseConfig>()?;
51///     println!("Database: {}:{}", db_config.host, db_config.port);
52///
53///     // Modify in place
54///     store.with_mut::<AppConfig, _, _>(|cfg| {
55///         cfg.debug = false;
56///     })?;
57///
58///     Ok(())
59/// }
60/// ```
61#[derive(Clone, Debug)]
62pub struct TypeStore {
63    items: Arc<Mutex<HashMap<TypeId, AnyValue>>>,
64}
65
66impl TypeStore {
67    /// Creates a new, empty TypeStore.
68    ///
69    /// # Examples
70    ///
71    /// ```
72    /// use sovran_typemap::TypeStore;
73    ///
74    /// let store = TypeStore::new();
75    /// ```
76    pub fn new() -> Self {
77        Self {
78            items: Arc::new(Mutex::new(HashMap::new())),
79        }
80    }
81
82    /// Stores a value, using its type as the key.
83    ///
84    /// If a value of this type already exists, it will be replaced.
85    ///
86    /// # Errors
87    ///
88    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
89    ///
90    /// # Examples
91    ///
92    /// ```
93    /// # use sovran_typemap::{TypeStore, MapError};
94    /// # fn main() -> Result<(), MapError> {
95    /// let store = TypeStore::new();
96    ///
97    /// store.set(42i32)?;
98    /// store.set("hello".to_string())?;
99    /// store.set(vec![1, 2, 3])?;
100    ///
101    /// // Overwrites the previous i32
102    /// store.set(100i32)?;
103    /// assert_eq!(store.get::<i32>()?, 100);
104    /// # Ok(())
105    /// # }
106    /// ```
107    pub fn set<V>(&self, value: V) -> Result<(), MapError>
108    where
109        V: 'static + Any + Send + Sync,
110    {
111        let mut store = self.items.lock().map_err(|_| MapError::LockError)?;
112        store.insert(TypeId::of::<V>(), AnyValue::new(value));
113        Ok(())
114    }
115
116    /// Stores a value generated by a closure.
117    ///
118    /// This is useful for lazy initialization or when value construction
119    /// should only happen if the lock can be acquired.
120    ///
121    /// # Errors
122    ///
123    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
124    ///
125    /// # Examples
126    ///
127    /// ```
128    /// # use sovran_typemap::{TypeStore, MapError};
129    /// # fn main() -> Result<(), MapError> {
130    /// let store = TypeStore::new();
131    ///
132    /// // Lazily construct a value
133    /// store.set_with(|| {
134    ///     vec![1, 2, 3, 4, 5]
135    /// })?;
136    ///
137    /// store.with::<Vec<i32>, _, _>(|v| {
138    ///     assert_eq!(v.len(), 5);
139    /// })?;
140    /// # Ok(())
141    /// # }
142    /// ```
143    pub fn set_with<V, F>(&self, f: F) -> Result<(), MapError>
144    where
145        V: 'static + Any + Send + Sync,
146        F: FnOnce() -> V,
147    {
148        let value = f();
149        self.set(value)
150    }
151
152    /// Retrieves a clone of a value by its type.
153    ///
154    /// # Errors
155    ///
156    /// - Returns `MapError::LockError` if the internal lock cannot be acquired
157    /// - Returns `MapError::KeyNotFound` if no value of this type exists
158    ///
159    /// # Examples
160    ///
161    /// ```
162    /// # use sovran_typemap::{TypeStore, MapError};
163    /// # fn main() -> Result<(), MapError> {
164    /// let store = TypeStore::new();
165    /// store.set(42i32)?;
166    ///
167    /// let value = store.get::<i32>()?;
168    /// assert_eq!(value, 42);
169    ///
170    /// // Type not found
171    /// match store.get::<String>() {
172    ///     Err(MapError::KeyNotFound(type_name)) => {
173    ///         println!("No value of type: {}", type_name);
174    ///     }
175    ///     _ => {}
176    /// }
177    /// # Ok(())
178    /// # }
179    /// ```
180    pub fn get<V>(&self) -> Result<V, MapError>
181    where
182        V: 'static + Clone,
183    {
184        self.with(|val: &V| val.clone())
185    }
186
187    /// Accesses a value by type with a read-only closure.
188    ///
189    /// # Errors
190    ///
191    /// - Returns `MapError::LockError` if the internal lock cannot be acquired
192    /// - Returns `MapError::KeyNotFound` if no value of this type exists
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// # use sovran_typemap::{TypeStore, MapError};
198    /// # fn main() -> Result<(), MapError> {
199    /// let store = TypeStore::new();
200    /// store.set(vec![1, 2, 3, 4, 5])?;
201    ///
202    /// let sum = store.with::<Vec<i32>, _, _>(|numbers| {
203    ///     numbers.iter().sum::<i32>()
204    /// })?;
205    /// assert_eq!(sum, 15);
206    /// # Ok(())
207    /// # }
208    /// ```
209    pub fn with<V: 'static, F, R>(&self, f: F) -> Result<R, MapError>
210    where
211        F: FnOnce(&V) -> R,
212    {
213        let guard = self.items.lock().map_err(|_| MapError::LockError)?;
214        let value = guard
215            .get(&TypeId::of::<V>())
216            .ok_or_else(|| MapError::KeyNotFound(type_name::<V>().to_string()))?;
217
218        // Type is guaranteed to match since TypeId is the key
219        let reference = value.downcast_ref::<V>().unwrap();
220        Ok(f(reference))
221    }
222
223    /// Accesses a value by type with a read-write closure.
224    ///
225    /// # Errors
226    ///
227    /// - Returns `MapError::LockError` if the internal lock cannot be acquired
228    /// - Returns `MapError::KeyNotFound` if no value of this type exists
229    ///
230    /// # Examples
231    ///
232    /// ```
233    /// # use sovran_typemap::{TypeStore, MapError};
234    /// # fn main() -> Result<(), MapError> {
235    /// let store = TypeStore::new();
236    /// store.set(vec![1, 2, 3])?;
237    ///
238    /// store.with_mut::<Vec<i32>, _, _>(|numbers| {
239    ///     numbers.push(4);
240    ///     numbers.push(5);
241    /// })?;
242    ///
243    /// let len = store.with::<Vec<i32>, _, _>(|v| v.len())?;
244    /// assert_eq!(len, 5);
245    /// # Ok(())
246    /// # }
247    /// ```
248    pub fn with_mut<V: 'static, F, R>(&self, f: F) -> Result<R, MapError>
249    where
250        F: FnOnce(&mut V) -> R,
251    {
252        let mut guard = self.items.lock().map_err(|_| MapError::LockError)?;
253        let value = guard
254            .get_mut(&TypeId::of::<V>())
255            .ok_or_else(|| MapError::KeyNotFound(type_name::<V>().to_string()))?;
256
257        // Type is guaranteed to match since TypeId is the key
258        let reference = value.downcast_mut::<V>().unwrap();
259        Ok(f(reference))
260    }
261
262    /// Removes a value by its type.
263    ///
264    /// # Errors
265    ///
266    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
267    ///
268    /// # Returns
269    ///
270    /// Returns `Ok(true)` if a value was removed, `Ok(false)` if no value
271    /// of that type existed.
272    ///
273    /// # Examples
274    ///
275    /// ```
276    /// # use sovran_typemap::{TypeStore, MapError};
277    /// # fn main() -> Result<(), MapError> {
278    /// let store = TypeStore::new();
279    /// store.set(42i32)?;
280    ///
281    /// assert!(store.remove::<i32>()?);
282    /// assert!(!store.remove::<i32>()?); // Already removed
283    /// # Ok(())
284    /// # }
285    /// ```
286    pub fn remove<V: 'static>(&self) -> Result<bool, MapError> {
287        let mut store = self.items.lock().map_err(|_| MapError::LockError)?;
288        Ok(store.remove(&TypeId::of::<V>()).is_some())
289    }
290
291    /// Checks if a value of the given type exists.
292    ///
293    /// # Errors
294    ///
295    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
296    ///
297    /// # Examples
298    ///
299    /// ```
300    /// # use sovran_typemap::{TypeStore, MapError};
301    /// # fn main() -> Result<(), MapError> {
302    /// let store = TypeStore::new();
303    ///
304    /// assert!(!store.contains::<i32>()?);
305    /// store.set(42i32)?;
306    /// assert!(store.contains::<i32>()?);
307    /// # Ok(())
308    /// # }
309    /// ```
310    pub fn contains<V: 'static>(&self) -> Result<bool, MapError> {
311        let store = self.items.lock().map_err(|_| MapError::LockError)?;
312        Ok(store.contains_key(&TypeId::of::<V>()))
313    }
314
315    /// Gets the number of values in the store.
316    ///
317    /// # Errors
318    ///
319    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
320    ///
321    /// # Examples
322    ///
323    /// ```
324    /// # use sovran_typemap::{TypeStore, MapError};
325    /// # fn main() -> Result<(), MapError> {
326    /// let store = TypeStore::new();
327    /// assert_eq!(store.len()?, 0);
328    ///
329    /// store.set(42i32)?;
330    /// store.set("hello".to_string())?;
331    /// assert_eq!(store.len()?, 2);
332    /// # Ok(())
333    /// # }
334    /// ```
335    pub fn len(&self) -> Result<usize, MapError> {
336        let store = self.items.lock().map_err(|_| MapError::LockError)?;
337        Ok(store.len())
338    }
339
340    /// Checks if the store is empty.
341    ///
342    /// # Errors
343    ///
344    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
345    ///
346    /// # Examples
347    ///
348    /// ```
349    /// # use sovran_typemap::{TypeStore, MapError};
350    /// # fn main() -> Result<(), MapError> {
351    /// let store = TypeStore::new();
352    /// assert!(store.is_empty()?);
353    ///
354    /// store.set(42i32)?;
355    /// assert!(!store.is_empty()?);
356    /// # Ok(())
357    /// # }
358    /// ```
359    pub fn is_empty(&self) -> Result<bool, MapError> {
360        let store = self.items.lock().map_err(|_| MapError::LockError)?;
361        Ok(store.is_empty())
362    }
363}
364
365impl Default for TypeStore {
366    fn default() -> Self {
367        Self::new()
368    }
369}
370
371#[cfg(test)]
372mod tests {
373    use super::*;
374
375    #[derive(Clone, Debug, PartialEq)]
376    struct TestConfig {
377        name: String,
378        value: i32,
379    }
380
381    #[derive(Clone, Debug, PartialEq)]
382    struct AnotherConfig {
383        enabled: bool,
384    }
385
386    #[test]
387    fn test_set_and_get() -> Result<(), MapError> {
388        let store = TypeStore::new();
389
390        store.set(TestConfig {
391            name: "test".to_string(),
392            value: 42,
393        })?;
394
395        let config = store.get::<TestConfig>()?;
396        assert_eq!(config.name, "test");
397        assert_eq!(config.value, 42);
398
399        Ok(())
400    }
401
402    #[test]
403    fn test_multiple_types() -> Result<(), MapError> {
404        let store = TypeStore::new();
405
406        store.set(TestConfig {
407            name: "test".to_string(),
408            value: 42,
409        })?;
410        store.set(AnotherConfig { enabled: true })?;
411        store.set(123i32)?;
412        store.set("hello".to_string())?;
413
414        assert_eq!(store.get::<TestConfig>()?.value, 42);
415        assert!(store.get::<AnotherConfig>()?.enabled);
416        assert_eq!(store.get::<i32>()?, 123);
417        assert_eq!(store.get::<String>()?, "hello");
418
419        Ok(())
420    }
421
422    #[test]
423    fn test_overwrite() -> Result<(), MapError> {
424        let store = TypeStore::new();
425
426        store.set(42i32)?;
427        assert_eq!(store.get::<i32>()?, 42);
428
429        store.set(100i32)?;
430        assert_eq!(store.get::<i32>()?, 100);
431
432        // Still only one item
433        assert_eq!(store.len()?, 1);
434
435        Ok(())
436    }
437
438    #[test]
439    fn test_with() -> Result<(), MapError> {
440        let store = TypeStore::new();
441        store.set(vec![1, 2, 3, 4, 5])?;
442
443        let sum = store.with::<Vec<i32>, _, _>(|v| v.iter().sum::<i32>())?;
444        assert_eq!(sum, 15);
445
446        Ok(())
447    }
448
449    #[test]
450    fn test_with_mut() -> Result<(), MapError> {
451        let store = TypeStore::new();
452        store.set(vec![1, 2, 3])?;
453
454        store.with_mut::<Vec<i32>, _, _>(|v| {
455            v.push(4);
456            v.push(5);
457        })?;
458
459        let len = store.with::<Vec<i32>, _, _>(|v| v.len())?;
460        assert_eq!(len, 5);
461
462        Ok(())
463    }
464
465    #[test]
466    fn test_remove() -> Result<(), MapError> {
467        let store = TypeStore::new();
468        store.set(42i32)?;
469
470        assert!(store.contains::<i32>()?);
471        assert!(store.remove::<i32>()?);
472        assert!(!store.contains::<i32>()?);
473        assert!(!store.remove::<i32>()?);
474
475        Ok(())
476    }
477
478    #[test]
479    fn test_contains() -> Result<(), MapError> {
480        let store = TypeStore::new();
481
482        assert!(!store.contains::<i32>()?);
483        store.set(42i32)?;
484        assert!(store.contains::<i32>()?);
485
486        Ok(())
487    }
488
489    #[test]
490    fn test_len_and_is_empty() -> Result<(), MapError> {
491        let store = TypeStore::new();
492
493        assert!(store.is_empty()?);
494        assert_eq!(store.len()?, 0);
495
496        store.set(42i32)?;
497        assert!(!store.is_empty()?);
498        assert_eq!(store.len()?, 1);
499
500        store.set("hello".to_string())?;
501        assert_eq!(store.len()?, 2);
502
503        store.remove::<i32>()?;
504        assert_eq!(store.len()?, 1);
505
506        Ok(())
507    }
508
509    #[test]
510    fn test_key_not_found_error() {
511        let store = TypeStore::new();
512
513        match store.get::<TestConfig>() {
514            Err(MapError::KeyNotFound(type_name)) => {
515                assert!(type_name.contains("TestConfig"));
516            }
517            _ => panic!("Expected KeyNotFound error"),
518        }
519    }
520
521    #[test]
522    fn test_set_with() -> Result<(), MapError> {
523        let store = TypeStore::new();
524
525        store.set_with(|| TestConfig {
526            name: "lazy".to_string(),
527            value: 99,
528        })?;
529
530        let config = store.get::<TestConfig>()?;
531        assert_eq!(config.name, "lazy");
532        assert_eq!(config.value, 99);
533
534        Ok(())
535    }
536
537    #[test]
538    fn test_thread_safety() -> Result<(), MapError> {
539        use std::sync::Arc;
540        use std::thread;
541
542        let store = Arc::new(TypeStore::new());
543        store.set(0i32)?;
544
545        let mut handles = vec![];
546
547        for _ in 0..10 {
548            let store = Arc::clone(&store);
549            handles.push(thread::spawn(move || {
550                for _ in 0..100 {
551                    store
552                        .with_mut::<i32, _, _>(|v| {
553                            *v += 1;
554                        })
555                        .unwrap();
556                }
557            }));
558        }
559
560        for handle in handles {
561            handle.join().unwrap();
562        }
563
564        assert_eq!(store.get::<i32>()?, 1000);
565
566        Ok(())
567    }
568}