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