sovran_typemap/
store.rs

1use std::any::Any;
2use std::collections::HashMap;
3use std::hash::Hash;
4use std::sync::{Arc, Mutex};
5
6use crate::any_value::AnyValue;
7use crate::error::StoreError;
8
9/// A thread-safe heterogeneous container with type-safety
10///
11/// `TypeStore` allows you to store values of different types in a single container
12/// while maintaining type-safety through runtime checks. It provides a convenient way
13/// to share state between components without requiring all components to know about all types.
14///
15/// # Examples
16///
17/// ```
18/// use sovran_typemap::{TypeStore, StoreError};
19///
20/// fn main() -> Result<(), StoreError> {
21///     // Create a new TypeStore with string keys
22///     let store = TypeStore::<String>::new();
23///
24///     // Store values of different types
25///     store.set("number".to_string(), 42i32)?;
26///     store.set("text".to_string(), "Hello, world!".to_string())?;
27///     store.set("flags".to_string(), vec![true, false, true])?;
28///
29///     // Retrieve values with type safety
30///     let num = store.get::<i32>(&"number".to_string())?;
31///     println!("Retrieved: {}", num);
32///
33///     // Use with_mut to modify values in place
34///     store.with_mut::<Vec<bool>, _, _>(&"flags".to_string(), |flags| {
35///         flags.push(true);
36///         println!("Updated flags: {:?}", flags);
37///     })?;
38///
39///     Ok(())
40/// }
41/// ```
42pub struct TypeStore<K> {
43    items: Arc<Mutex<HashMap<K, AnyValue>>>,
44}
45
46impl<K> TypeStore<K>
47where
48    K: Clone + Eq + Hash,
49{
50    /// Creates a new, empty TypeStore
51    ///
52    /// # Examples
53    ///
54    /// ```
55    /// use sovran_typemap::TypeStore;
56    ///
57    /// // Create a TypeStore with String keys
58    /// let string_store = TypeStore::<String>::new();
59    ///
60    /// // Create a TypeStore with numeric keys
61    /// let int_store = TypeStore::<u32>::new();
62    /// ```
63    pub fn new() -> Self {
64        Self {
65            items: Arc::new(Mutex::new(HashMap::new())),
66        }
67    }
68
69    /// Stores a value of any type that implements Any, Send, and Sync
70    ///
71    /// # Errors
72    ///
73    /// Returns `StoreError::LockError` if the internal lock cannot be acquired.
74    ///
75    /// # Examples
76    ///
77    /// ```
78    /// # use sovran_typemap::{TypeStore, StoreError};
79    /// # fn main() -> Result<(), StoreError> {
80    /// let store: TypeStore<String> = TypeStore::new();
81    ///
82    /// // Store values of different types
83    /// store.set("number".to_string(), 42i32)?;
84    /// store.set("text".to_string(), "Hello, world!".to_string())?;
85    /// store.set("complex".to_string(), (1, "tuple", true))?;
86    ///
87    /// // Overwrite an existing value
88    /// store.set("number".to_string(), 100i32)?;
89    /// # Ok(())
90    /// # }
91    /// ```
92    pub fn set<V>(&self, key: K, value: V) -> Result<(), StoreError>
93    where
94        V: 'static + Any + Send + Sync,
95    {
96        let mut store = self.items.lock().map_err(|_| StoreError::LockError)?;
97        store.insert(key, AnyValue::new(value));
98        Ok(())
99    }
100
101    /// Stores a value generated by a closure
102    ///
103    /// This is useful for lazy initialization or complex value construction where
104    /// you want to avoid creating the value if the lock can't be acquired.
105    ///
106    /// # Errors
107    ///
108    /// Returns `StoreError::LockError` if the internal lock cannot be acquired.
109    ///
110    /// # Examples
111    ///
112    /// ```
113    /// # use sovran_typemap::{TypeStore, StoreError};
114    /// # fn main() -> Result<(), StoreError> {
115    /// let store: TypeStore<String> = TypeStore::new();
116    ///
117    /// // Lazily construct a complex value
118    /// store.set_with("user_data".to_string(), || {
119    ///     // Imagine this is an expensive operation
120    ///     let mut data = Vec::new();
121    ///     for i in 0..1000 {
122    ///         data.push(i * 2);
123    ///     }
124    ///     data
125    /// })?;
126    ///
127    /// // Access the constructed data
128    /// store.with(&"user_data".to_string(), |data: &Vec<i32>| {
129    ///     println!("First value: {}", data.first().unwrap_or(&0));
130    /// })?;
131    /// # Ok(())
132    /// # }
133    /// ```
134    ///
135    /// Handling potential errors:
136    ///
137    /// ```
138    /// # use sovran_typemap::{TypeStore, StoreError};
139    /// # fn main() {
140    /// let store: TypeStore<String> = TypeStore::new();
141    ///
142    /// // Handle potential errors from set_with
143    /// match store.set_with("config".to_string(), || {
144    ///     // In a real scenario, this might load from a file
145    ///     std::collections::HashMap::<String, String>::new()
146    /// }) {
147    ///     Ok(()) => println!("Configuration stored successfully"),
148    ///     Err(StoreError::LockError) => eprintln!("Failed to acquire lock - try again later"),
149    ///     Err(e) => eprintln!("Unexpected error: {}", e),
150    /// }
151    /// # }
152    /// ```
153    pub fn set_with<V, F>(&self, key: K, f: F) -> Result<(), StoreError>
154    where
155        V: 'static + Any + Send + Sync,
156        F: FnOnce() -> V,
157    {
158        let value = f();
159        self.set(key, value)
160    }
161
162    /// Retrieves a clone of a value from the store
163    ///
164    /// This provides a convenient way to get a copy of a value when the `Clone`
165    /// trait is available. For more complex operations or to avoid cloning,
166    /// use `with` instead.
167    ///
168    /// # Type Parameters
169    ///
170    /// * `V` - The type of the value to retrieve. Must match the type that was stored.
171    ///
172    /// # Errors
173    ///
174    /// - Returns `StoreError::LockError` if the internal lock cannot be acquired
175    /// - Returns `StoreError::KeyNotFound` if the key doesn't exist in the store
176    /// - Returns `StoreError::TypeMismatch` if the value exists but has a different type
177    ///
178    /// # Examples
179    ///
180    /// ```
181    /// # use sovran_typemap::{TypeStore, StoreError};
182    /// # fn main() -> Result<(), StoreError> {
183    /// let store: TypeStore<String> = TypeStore::new();
184    /// store.set("answer".to_string(), 42i32)?;
185    ///
186    /// // Get a clone of the value
187    /// let value = store.get::<i32>(&"answer".to_string())?;
188    /// assert_eq!(value, 42);
189    ///
190    /// // Handle possible errors
191    /// match store.get::<String>(&"non_existent".to_string()) {
192    ///     Ok(value) => println!("Value: {}", value),
193    ///     Err(StoreError::KeyNotFound) => println!("Key not found"),
194    ///     Err(StoreError::TypeMismatch) => println!("Type mismatch"),
195    ///     Err(StoreError::LockError) => println!("Failed to acquire lock"),
196    /// }
197    ///
198    /// // Type mismatch example
199    /// store.set("name".to_string(), "Alice".to_string())?;
200    /// match store.get::<i32>(&"name".to_string()) {
201    ///     Ok(value) => println!("Value: {}", value),
202    ///     Err(StoreError::TypeMismatch) => println!("The value is not an i32"),
203    ///     Err(e) => println!("Other error: {}", e),
204    /// }
205    /// # Ok(())
206    /// # }
207    /// ```
208    pub fn get<V>(&self, key: &K) -> Result<V, StoreError>
209    where
210        V: 'static + Clone,
211    {
212        self.with(key, |val: &V| val.clone())
213    }
214
215    /// Gets a value by executing a closure with read access
216    ///
217    /// This method allows for arbitrary operations on the stored value without
218    /// requiring the value to implement `Clone`. It's useful for inspecting values,
219    /// computing derived values, or performing operations that don't require ownership.
220    ///
221    /// # Type Parameters
222    ///
223    /// * `V` - The type of the value to access. Must match the type that was stored.
224    /// * `F` - A closure that takes a reference to the value and returns a result.
225    /// * `R` - The return type of the closure.
226    ///
227    /// # Errors
228    ///
229    /// - Returns `StoreError::LockError` if the internal lock cannot be acquired
230    /// - Returns `StoreError::KeyNotFound` if the key doesn't exist in the store
231    /// - Returns `StoreError::TypeMismatch` if the value exists but has a different type
232    ///
233    /// # Examples
234    ///
235    /// ```
236    /// # use sovran_typemap::{TypeStore, StoreError};
237    /// # fn main() -> Result<(), StoreError> {
238    /// let store: TypeStore<String> = TypeStore::new();
239    /// store.set("users".to_string(), vec!["Alice", "Bob", "Charlie"])?;
240    ///
241    /// // Read and compute something from the value
242    /// let user_count = store.with(&"users".to_string(), |users: &Vec<&str>| users.len())?;
243    /// println!("Number of users: {}", user_count);
244    ///
245    /// // Checking if a specific value exists
246    /// let has_alice = store.with(&"users".to_string(), |users: &Vec<&str>| {
247    ///     users.contains(&"Alice")
248    /// })?;
249    ///
250    /// // Handle potential errors with pattern matching
251    /// match store.with(&"settings".to_string(), |settings: &std::collections::HashMap<String, String>| {
252    ///     settings.get("theme").cloned()
253    /// }) {
254    ///     Ok(Some(theme)) => println!("Current theme: {}", theme),
255    ///     Ok(None) => println!("Theme setting not found"),
256    ///     Err(StoreError::KeyNotFound) => println!("Settings not initialized"),
257    ///     Err(StoreError::TypeMismatch) => println!("Settings has unexpected type"),
258    ///     Err(e) => println!("Error: {}", e),
259    /// }
260    /// # Ok(())
261    /// # }
262    /// ```
263    pub fn with<V: 'static, F, R>(&self, key: &K, f: F) -> Result<R, StoreError>
264    where
265        F: FnOnce(&V) -> R,
266    {
267        let guard = self.items.lock().map_err(|_| StoreError::LockError)?;
268        let value = guard.get(key).ok_or(StoreError::KeyNotFound)?;
269
270        if !value.is_type::<V>() {
271            return Err(StoreError::TypeMismatch);
272        }
273
274        // This is safe because we've checked the type
275        let reference = value.downcast_ref::<V>().unwrap();
276        Ok(f(reference))
277    }
278
279    /// Gets a value by executing a closure with write access
280    ///
281    /// This method allows for modifying the stored value in place without
282    /// replacing it entirely. It's useful for updating collections or
283    /// complex structures.
284    ///
285    /// # Type Parameters
286    ///
287    /// * `V` - The type of the value to access. Must match the type that was stored.
288    /// * `F` - A closure that takes a mutable reference to the value and returns a result.
289    /// * `R` - The return type of the closure.
290    ///
291    /// # Errors
292    ///
293    /// - Returns `StoreError::LockError` if the internal lock cannot be acquired
294    /// - Returns `StoreError::KeyNotFound` if the key doesn't exist in the store
295    /// - Returns `StoreError::TypeMismatch` if the value exists but has a different type
296    ///
297    /// # Examples
298    ///
299    /// ```
300    /// # use sovran_typemap::{TypeStore, StoreError};
301    /// # fn main() -> Result<(), StoreError> {
302    /// let store: TypeStore<String> = TypeStore::new();
303    ///
304    /// // Initialize a vector
305    /// store.set("numbers".to_string(), vec![1, 2, 3])?;
306    ///
307    /// // Modify the vector in place
308    /// store.with_mut(&"numbers".to_string(), |numbers: &mut Vec<i32>| {
309    ///     numbers.push(4);
310    ///     numbers.push(5);
311    /// })?;
312    ///
313    /// // Verify the modification
314    /// let count = store.with(&"numbers".to_string(), |numbers: &Vec<i32>| {
315    ///     assert_eq!(numbers, &[1, 2, 3, 4, 5]);
316    ///     numbers.len()
317    /// })?;
318    /// println!("Vector now has {} elements", count);
319    ///
320    /// // Example with a HashMap
321    /// store.set("counters".to_string(), std::collections::HashMap::<String, i32>::new())?;
322    ///
323    /// // Update counter values
324    /// let result = store.with_mut(&"counters".to_string(), |counters: &mut std::collections::HashMap<String, i32>| {
325    ///     *counters.entry("visits".to_string()).or_insert(0) += 1;
326    ///     counters.get("visits").copied() // Return current count
327    /// })?;
328    /// println!("Visit count: {}", result.unwrap_or(0));
329    ///
330    /// // Error handling example
331    /// match store.with_mut(&"config".to_string(), |config: &mut std::collections::HashMap<String, String>| {
332    ///     config.insert("theme".to_string(), "dark".to_string())
333    /// }) {
334    ///     Ok(old_theme) => println!("Previous theme: {:?}", old_theme),
335    ///     Err(StoreError::KeyNotFound) => println!("Config not found"),
336    ///     Err(StoreError::TypeMismatch) => println!("Config has wrong type"),
337    ///     Err(e) => println!("Error: {}", e),
338    /// }
339    /// # Ok(())
340    /// # }
341    /// ```
342    pub fn with_mut<V: 'static, F, R>(&self, key: &K, f: F) -> Result<R, StoreError>
343    where
344        F: FnOnce(&mut V) -> R,
345    {
346        let mut guard = self.items.lock().map_err(|_| StoreError::LockError)?;
347        let value = guard.get_mut(key).ok_or(StoreError::KeyNotFound)?;
348
349        if !value.is_type::<V>() {
350            return Err(StoreError::TypeMismatch);
351        }
352
353        // This is safe because we've checked the type
354        let reference = value.downcast_mut::<V>().unwrap();
355        Ok(f(reference))
356    }
357
358    /// Removes a value from the store
359    ///
360    /// # Errors
361    ///
362    /// Returns `StoreError::LockError` if the internal lock cannot be acquired.
363    ///
364    /// # Returns
365    ///
366    /// Returns `Ok(true)` if the key was present and the value was removed.
367    /// Returns `Ok(false)` if the key was not present.
368    ///
369    /// # Examples
370    ///
371    /// ```
372    /// # use sovran_typemap::{TypeStore, StoreError};
373    /// # fn main() -> Result<(), StoreError> {
374    /// let store: TypeStore<String> = TypeStore::new();
375    /// store.set("temp".to_string(), "This is temporary".to_string())?;
376    ///
377    /// // Remove the value
378    /// let was_removed = store.remove(&"temp".to_string())?;
379    /// assert!(was_removed);
380    ///
381    /// // Check that it's gone
382    /// match store.get::<String>(&"temp".to_string()) {
383    ///     Err(StoreError::KeyNotFound) => println!("Key was successfully removed"),
384    ///     Ok(_) => println!("Key still exists"),
385    ///     Err(e) => println!("Error: {}", e),
386    /// }
387    ///
388    /// // Removing a non-existent key
389    /// let was_removed = store.remove(&"nonexistent".to_string())?;
390    /// assert!(!was_removed);
391    ///
392    /// // Using pattern matching for error handling
393    /// match store.remove(&"another_key".to_string()) {
394    ///     Ok(true) => println!("Key was found and removed"),
395    ///     Ok(false) => println!("Key did not exist"),
396    ///     Err(StoreError::LockError) => println!("Failed to acquire lock"),
397    ///     Err(e) => println!("Unexpected error: {}", e),
398    /// }
399    /// # Ok(())
400    /// # }
401    /// ```
402    pub fn remove(&self, key: &K) -> Result<bool, StoreError> {
403        let mut store = self.items.lock().map_err(|_| StoreError::LockError)?;
404        Ok(store.remove(key).is_some())
405    }
406
407    /// Checks if a key exists in the store
408    ///
409    /// This method only checks for the existence of the key and does not validate
410    /// the type of the stored value.
411    ///
412    /// # Errors
413    ///
414    /// Returns `StoreError::LockError` if the internal lock cannot be acquired.
415    ///
416    /// # Examples
417    ///
418    /// ```
419    /// # use sovran_typemap::{TypeStore, StoreError};
420    /// # fn main() -> Result<(), StoreError> {
421    /// let store: TypeStore<String> = TypeStore::new();
422    /// store.set("config".to_string(), std::collections::HashMap::<String, String>::new())?;
423    ///
424    /// // Check if a key exists
425    /// let has_config = store.contains_key(&"config".to_string())?;
426    /// assert!(has_config);
427    ///
428    /// let has_users = store.contains_key(&"users".to_string())?;
429    /// assert!(!has_users);
430    ///
431    /// // Use in conditional logic
432    /// if !store.contains_key(&"initialized".to_string())? {
433    ///     store.set("initialized".to_string(), true)?;
434    ///     println!("Store initialized for the first time");
435    /// }
436    ///
437    /// // Error handling
438    /// match store.contains_key(&"settings".to_string()) {
439    ///     Ok(true) => println!("Settings exist"),
440    ///     Ok(false) => println!("Settings do not exist"),
441    ///     Err(e) => println!("Error checking settings: {}", e),
442    /// }
443    /// # Ok(())
444    /// # }
445    /// ```
446    pub fn contains_key(&self, key: &K) -> Result<bool, StoreError> {
447        let store = self.items.lock().map_err(|_| StoreError::LockError)?;
448        Ok(store.contains_key(key))
449    }
450
451    /// Gets all keys in the store
452    ///
453    /// # Errors
454    ///
455    /// Returns `StoreError::LockError` if the internal lock cannot be acquired.
456    ///
457    /// # Examples
458    ///
459    /// ```
460    /// # use sovran_typemap::{TypeStore, StoreError};
461    /// # fn main() -> Result<(), StoreError> {
462    /// let store: TypeStore<String> = TypeStore::new();
463    /// store.set("user".to_string(), "Alice".to_string())?;
464    /// store.set("count".to_string(), 42i32)?;
465    /// store.set("active".to_string(), true)?;
466    ///
467    /// // Get all keys
468    /// let keys = store.keys()?;
469    ///
470    /// // Keys are returned in arbitrary order, so sort for stable testing
471    /// let mut sorted_keys = keys.clone();
472    /// sorted_keys.sort();
473    ///
474    /// assert_eq!(sorted_keys, vec!["active".to_string(), "count".to_string(), "user".to_string()]);
475    /// println!("Store contains {} keys", keys.len());
476    ///
477    /// // Use keys to iterate over stored values
478    /// for key in keys {
479    ///     // We need to handle different types differently
480    ///     if let Ok(value) = store.get::<String>(&key) {
481    ///         println!("{}: String = {}", key, value);
482    ///     } else if let Ok(value) = store.get::<i32>(&key) {
483    ///         println!("{}: i32 = {}", key, value);
484    ///     } else if let Ok(value) = store.get::<bool>(&key) {
485    ///         println!("{}: bool = {}", key, value);
486    ///     } else {
487    ///         println!("{}: unknown type", key);
488    ///     }
489    /// }
490    ///
491    /// // Error handling
492    /// match store.keys() {
493    ///     Ok(keys) => println!("Found {} keys", keys.len()),
494    ///     Err(StoreError::LockError) => println!("Failed to acquire lock"),
495    ///     Err(e) => println!("Unexpected error: {}", e),
496    /// }
497    /// # Ok(())
498    /// # }
499    /// ```
500    pub fn keys(&self) -> Result<Vec<K>, StoreError>
501    where
502        K: Clone,
503    {
504        let store = self.items.lock().map_err(|_| StoreError::LockError)?;
505        Ok(store.keys().cloned().collect())
506    }
507
508    /// Gets the number of items in the store
509    ///
510    /// # Errors
511    ///
512    /// Returns `StoreError::LockError` if the internal lock cannot be acquired.
513    ///
514    /// # Examples
515    ///
516    /// ```
517    /// # use sovran_typemap::{TypeStore, StoreError};
518    /// # fn main() -> Result<(), StoreError> {
519    /// let store: TypeStore<String> = TypeStore::new();
520    ///
521    /// // Initially empty
522    /// assert_eq!(store.len()?, 0);
523    ///
524    /// // Add some items
525    /// store.set("one".to_string(), 1)?;
526    /// store.set("two".to_string(), 2)?;
527    ///
528    /// // Check the count
529    /// assert_eq!(store.len()?, 2);
530    ///
531    /// // Use in conditional logic
532    /// if store.len()? > 10 {
533    ///     println!("Store has many items");
534    /// } else {
535    ///     println!("Store has few items");
536    /// }
537    ///
538    /// // Error handling
539    /// match store.len() {
540    ///     Ok(count) => println!("Store contains {} items", count),
541    ///     Err(StoreError::LockError) => println!("Failed to acquire lock"),
542    ///     Err(e) => println!("Unexpected error: {}", e),
543    /// }
544    /// # Ok(())
545    /// # }
546    /// ```
547    pub fn len(&self) -> Result<usize, StoreError> {
548        let store = self.items.lock().map_err(|_| StoreError::LockError)?;
549        Ok(store.len())
550    }
551
552    /// Checks if the store is empty
553    ///
554    /// # Errors
555    ///
556    /// Returns `StoreError::LockError` if the internal lock cannot be acquired.
557    ///
558    /// # Examples
559    ///
560    /// ```
561    /// # use sovran_typemap::{TypeStore, StoreError};
562    /// # fn main() -> Result<(), StoreError> {
563    /// let store: TypeStore<String> = TypeStore::new();
564    ///
565    /// // New store is empty
566    /// assert!(store.is_empty()?);
567    ///
568    /// // Add an item
569    /// store.set("key".to_string(), "value".to_string())?;
570    ///
571    /// // Now it's not empty
572    /// assert!(!store.is_empty()?);
573    ///
574    /// // Use in conditional logic
575    /// if store.is_empty()? {
576    ///     println!("Store is empty");
577    /// } else {
578    ///     println!("Store contains items");
579    /// }
580    ///
581    /// // Error handling
582    /// match store.is_empty() {
583    ///     Ok(true) => println!("Store is empty"),
584    ///     Ok(false) => println!("Store has items"),
585    ///     Err(StoreError::LockError) => println!("Failed to acquire lock"),
586    ///     Err(e) => println!("Unexpected error: {}", e),
587    /// }
588    /// # Ok(())
589    /// # }
590    /// ```
591    pub fn is_empty(&self) -> Result<bool, StoreError> {
592        let store = self.items.lock().map_err(|_| StoreError::LockError)?;
593        Ok(store.is_empty())
594    }
595}
596
597impl<K> Default for TypeStore<K>
598where
599    K: Clone + Eq + Hash,
600{
601    fn default() -> Self {
602        Self::new()
603    }
604}