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}