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}