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