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