sovran_typemap/
map.rs

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