sovran_typemap/
typed.rs

1use crate::error::MapError;
2use std::collections::HashMap;
3use std::fmt::Debug;
4use std::hash::Hash;
5use std::sync::{Arc, Mutex};
6
7/// A thread-safe map that stores values of a specific type
8///
9/// `TypeMapV` allows you to create a type-safe, thread-safe map where all values
10/// must be of the same type (or implement the same trait). This is particularly
11/// useful for storing collections of trait objects or other homogeneous values.
12///
13/// # Examples
14///
15/// ```
16/// use sovran_typemap::{TypeMapV, MapError};
17///
18/// // Store trait objects
19/// trait Handler: Send + Sync {
20///     fn handle(&self) -> Result<(), MapError>;
21/// }
22///
23/// let store = TypeMapV::<String, Box<dyn Handler>>::new();
24///
25/// // Apply an operation to all handlers
26/// let result = store.apply(|key, handler| {
27///     println!("Running handler {}", key);
28///     handler.handle()
29/// });
30/// ```
31#[derive(Clone, Debug)]
32pub struct TypeMapV<K, V>
33where
34    K: Clone + Eq + Hash + Debug,
35    V: Send + Sync,
36{
37    items: Arc<Mutex<HashMap<K, V>>>,
38}
39
40impl<K, V> TypeMapV<K, V>
41where
42    K: Clone + Eq + Hash + Debug,
43    V: Send + Sync,
44{
45    /// Creates a new, empty TypeMapV
46    ///
47    /// # Examples
48    ///
49    /// ```
50    /// use sovran_typemap::TypeMapV;
51    ///
52    /// // Create a map storing strings
53    /// let string_store = TypeMapV::<String, String>::new();
54    ///
55    /// // Create a map storing trait objects
56    /// trait MyTrait: Send + Sync {}
57    /// let trait_store = TypeMapV::<u32, Box<dyn MyTrait>>::new();
58    /// ```
59    pub fn new() -> Self {
60        Self {
61            items: Arc::new(Mutex::new(HashMap::new())),
62        }
63    }
64
65    /// Stores a value in the map
66    ///
67    /// # Errors
68    ///
69    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
70    pub fn set(&self, key: K, value: V) -> Result<(), MapError> {
71        let mut store = self.items.lock().map_err(|_| MapError::LockError)?;
72        store.insert(key, value);
73        Ok(())
74    }
75
76    /// Retrieves a clone of a value from the map
77    ///
78    /// # Errors
79    ///
80    /// - Returns `MapError::LockError` if the internal lock cannot be acquired
81    /// - Returns `MapError::KeyNotFound` if the key doesn't exist
82    pub fn get(&self, key: &K) -> Result<V, MapError>
83    where
84        V: Clone,
85    {
86        let store = self.items.lock().map_err(|_| MapError::LockError)?;
87        store
88            .get(key)
89            .cloned()
90            .ok_or_else(|| MapError::KeyNotFound(format!("{:?}", key)))
91    }
92
93    /// Removes a value from the map
94    ///
95    /// # Errors
96    ///
97    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
98    ///
99    /// # Returns
100    ///
101    /// Returns `Ok(true)` if the key was present and removed, `Ok(false)` if not present.
102    pub fn remove(&self, key: &K) -> Result<bool, MapError> {
103        let mut store = self.items.lock().map_err(|_| MapError::LockError)?;
104        Ok(store.remove(key).is_some())
105    }
106
107    /// Applies a function to all key-value pairs in the map
108    ///
109    /// This method allows you to perform operations on all stored values while
110    /// maintaining thread safety. The function is called with a reference to both
111    /// the key and value for each entry.
112    ///
113    /// # Examples
114    ///
115    /// ```
116    /// # use sovran_typemap::{TypeMapV, MapError};
117    /// trait Handler: Send + Sync {
118    ///     fn handle(&self) -> Result<(), MapError>;
119    /// }
120    ///
121    /// let store = TypeMapV::<String, Box<dyn Handler>>::new();
122    ///
123    /// // Apply to all handlers
124    /// let result = store.apply(|key, handler| {
125    ///     handler.handle().map_err(|_| MapError::LockError)
126    /// });
127    /// ```
128    ///
129    /// # Errors
130    ///
131    /// Returns `MapError::LockError` if the internal lock cannot be acquired,
132    /// or any error returned by the provided function.
133    pub fn apply<F>(&self, mut f: F) -> Result<(), MapError>
134    where
135        F: FnMut(&K, &V) -> Result<(), MapError>,
136    {
137        let store = self.items.lock().map_err(|_| MapError::LockError)?;
138        for (key, value) in store.iter() {
139            f(key, value)?;
140        }
141        Ok(())
142    }
143
144    /// Returns the number of entries in the map
145    ///
146    /// # Errors
147    ///
148    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
149    pub fn len(&self) -> Result<usize, MapError> {
150        let store = self.items.lock().map_err(|_| MapError::LockError)?;
151        Ok(store.len())
152    }
153
154    /// Returns true if the map contains no entries
155    ///
156    /// # Errors
157    ///
158    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
159    pub fn is_empty(&self) -> Result<bool, MapError> {
160        let store = self.items.lock().map_err(|_| MapError::LockError)?;
161        Ok(store.is_empty())
162    }
163
164    /// Returns true if the map contains the specified key
165    ///
166    /// # Errors
167    ///
168    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
169    pub fn contains_key(&self, key: &K) -> Result<bool, MapError> {
170        let store = self.items.lock().map_err(|_| MapError::LockError)?;
171        Ok(store.contains_key(key))
172    }
173
174    /// Returns a vector of all keys in the map
175    ///
176    /// # Errors
177    ///
178    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
179    pub fn keys(&self) -> Result<Vec<K>, MapError>
180    where
181        K: Clone,
182    {
183        let store = self.items.lock().map_err(|_| MapError::LockError)?;
184        Ok(store.keys().cloned().collect())
185    }
186
187    /// Returns a vector of all values in the map
188    ///
189    /// # Errors
190    ///
191    /// Returns `MapError::LockError` if the internal lock cannot be acquired.
192    pub fn values(&self) -> Result<Vec<V>, MapError>
193    where
194        V: Clone,
195    {
196        let store = self.items.lock().map_err(|_| MapError::LockError)?;
197        Ok(store.values().cloned().collect())
198    }
199}
200
201impl<K, V> Default for TypeMapV<K, V>
202where
203    K: Clone + Eq + Hash + Debug,
204    V: Send + Sync,
205{
206    fn default() -> Self {
207        Self::new()
208    }
209}