sovran_typemap/store.rs
1// src/store.rs
2use std::any::{type_name, Any, TypeId};
3use std::collections::HashMap;
4use std::sync::{Arc, Mutex};
5
6use crate::any_value::AnyValue;
7use crate::error::MapError;
8
9/// A thread-safe container that stores exactly one value per type.
10///
11/// `TypeStore` provides a simple way to store and retrieve values using their
12/// type as the key. This is useful for dependency injection, service locators,
13/// and managing application-wide state without explicit key management.
14///
15/// Unlike `TypeMap` which uses explicit keys, `TypeStore` uses the type itself
16/// as the key, meaning you can only store one value of each type.
17///
18/// # Examples
19///
20/// ```
21/// use sovran_typemap::{TypeStore, MapError};
22///
23/// #[derive(Clone, Debug)]
24/// struct DatabaseConfig {
25/// host: String,
26/// port: u16,
27/// }
28///
29/// #[derive(Clone, Debug)]
30/// struct AppConfig {
31/// name: String,
32/// debug: bool,
33/// }
34///
35/// fn main() -> Result<(), MapError> {
36/// let store = TypeStore::new();
37///
38/// // Store configurations by type
39/// store.set(DatabaseConfig {
40/// host: "localhost".to_string(),
41/// port: 5432,
42/// })?;
43///
44/// store.set(AppConfig {
45/// name: "MyApp".to_string(),
46/// debug: true,
47/// })?;
48///
49/// // Retrieve by type - no key needed
50/// let db_config = store.get::<DatabaseConfig>()?;
51/// println!("Database: {}:{}", db_config.host, db_config.port);
52///
53/// // Modify in place
54/// store.with_mut::<AppConfig, _, _>(|cfg| {
55/// cfg.debug = false;
56/// })?;
57///
58/// Ok(())
59/// }
60/// ```
61#[derive(Clone, Debug)]
62pub struct TypeStore {
63 items: Arc<Mutex<HashMap<TypeId, AnyValue>>>,
64}
65
66impl TypeStore {
67 /// Creates a new, empty TypeStore.
68 ///
69 /// # Examples
70 ///
71 /// ```
72 /// use sovran_typemap::TypeStore;
73 ///
74 /// let store = TypeStore::new();
75 /// ```
76 pub fn new() -> Self {
77 Self {
78 items: Arc::new(Mutex::new(HashMap::new())),
79 }
80 }
81
82 /// Stores a value, using its type as the key.
83 ///
84 /// If a value of this type already exists, it will be replaced.
85 ///
86 /// # Errors
87 ///
88 /// Returns `MapError::LockError` if the internal lock cannot be acquired.
89 ///
90 /// # Examples
91 ///
92 /// ```
93 /// # use sovran_typemap::{TypeStore, MapError};
94 /// # fn main() -> Result<(), MapError> {
95 /// let store = TypeStore::new();
96 ///
97 /// store.set(42i32)?;
98 /// store.set("hello".to_string())?;
99 /// store.set(vec![1, 2, 3])?;
100 ///
101 /// // Overwrites the previous i32
102 /// store.set(100i32)?;
103 /// assert_eq!(store.get::<i32>()?, 100);
104 /// # Ok(())
105 /// # }
106 /// ```
107 pub fn set<V>(&self, value: V) -> Result<(), MapError>
108 where
109 V: 'static + Any + Send + Sync,
110 {
111 let mut store = self.items.lock().map_err(|_| MapError::LockError)?;
112 store.insert(TypeId::of::<V>(), AnyValue::new(value));
113 Ok(())
114 }
115
116 /// Stores a value generated by a closure.
117 ///
118 /// This is useful for lazy initialization or when value construction
119 /// should only happen if the lock can be acquired.
120 ///
121 /// # Errors
122 ///
123 /// Returns `MapError::LockError` if the internal lock cannot be acquired.
124 ///
125 /// # Examples
126 ///
127 /// ```
128 /// # use sovran_typemap::{TypeStore, MapError};
129 /// # fn main() -> Result<(), MapError> {
130 /// let store = TypeStore::new();
131 ///
132 /// // Lazily construct a value
133 /// store.set_with(|| {
134 /// vec![1, 2, 3, 4, 5]
135 /// })?;
136 ///
137 /// store.with::<Vec<i32>, _, _>(|v| {
138 /// assert_eq!(v.len(), 5);
139 /// })?;
140 /// # Ok(())
141 /// # }
142 /// ```
143 pub fn set_with<V, F>(&self, f: F) -> Result<(), MapError>
144 where
145 V: 'static + Any + Send + Sync,
146 F: FnOnce() -> V,
147 {
148 let value = f();
149 self.set(value)
150 }
151
152 /// Retrieves a clone of a value by its type.
153 ///
154 /// # Errors
155 ///
156 /// - Returns `MapError::LockError` if the internal lock cannot be acquired
157 /// - Returns `MapError::KeyNotFound` if no value of this type exists
158 ///
159 /// # Examples
160 ///
161 /// ```
162 /// # use sovran_typemap::{TypeStore, MapError};
163 /// # fn main() -> Result<(), MapError> {
164 /// let store = TypeStore::new();
165 /// store.set(42i32)?;
166 ///
167 /// let value = store.get::<i32>()?;
168 /// assert_eq!(value, 42);
169 ///
170 /// // Type not found
171 /// match store.get::<String>() {
172 /// Err(MapError::KeyNotFound(type_name)) => {
173 /// println!("No value of type: {}", type_name);
174 /// }
175 /// _ => {}
176 /// }
177 /// # Ok(())
178 /// # }
179 /// ```
180 pub fn get<V>(&self) -> Result<V, MapError>
181 where
182 V: 'static + Clone,
183 {
184 self.with(|val: &V| val.clone())
185 }
186
187 /// Accesses a value by type with a read-only closure.
188 ///
189 /// # Errors
190 ///
191 /// - Returns `MapError::LockError` if the internal lock cannot be acquired
192 /// - Returns `MapError::KeyNotFound` if no value of this type exists
193 ///
194 /// # Examples
195 ///
196 /// ```
197 /// # use sovran_typemap::{TypeStore, MapError};
198 /// # fn main() -> Result<(), MapError> {
199 /// let store = TypeStore::new();
200 /// store.set(vec![1, 2, 3, 4, 5])?;
201 ///
202 /// let sum = store.with::<Vec<i32>, _, _>(|numbers| {
203 /// numbers.iter().sum::<i32>()
204 /// })?;
205 /// assert_eq!(sum, 15);
206 /// # Ok(())
207 /// # }
208 /// ```
209 pub fn with<V: 'static, F, R>(&self, f: F) -> Result<R, MapError>
210 where
211 F: FnOnce(&V) -> R,
212 {
213 let guard = self.items.lock().map_err(|_| MapError::LockError)?;
214 let value = guard
215 .get(&TypeId::of::<V>())
216 .ok_or_else(|| MapError::KeyNotFound(type_name::<V>().to_string()))?;
217
218 // Type is guaranteed to match since TypeId is the key
219 let reference = value.downcast_ref::<V>().unwrap();
220 Ok(f(reference))
221 }
222
223 /// Accesses a value by type with a read-write closure.
224 ///
225 /// # Errors
226 ///
227 /// - Returns `MapError::LockError` if the internal lock cannot be acquired
228 /// - Returns `MapError::KeyNotFound` if no value of this type exists
229 ///
230 /// # Examples
231 ///
232 /// ```
233 /// # use sovran_typemap::{TypeStore, MapError};
234 /// # fn main() -> Result<(), MapError> {
235 /// let store = TypeStore::new();
236 /// store.set(vec![1, 2, 3])?;
237 ///
238 /// store.with_mut::<Vec<i32>, _, _>(|numbers| {
239 /// numbers.push(4);
240 /// numbers.push(5);
241 /// })?;
242 ///
243 /// let len = store.with::<Vec<i32>, _, _>(|v| v.len())?;
244 /// assert_eq!(len, 5);
245 /// # Ok(())
246 /// # }
247 /// ```
248 pub fn with_mut<V: 'static, F, R>(&self, f: F) -> Result<R, MapError>
249 where
250 F: FnOnce(&mut V) -> R,
251 {
252 let mut guard = self.items.lock().map_err(|_| MapError::LockError)?;
253 let value = guard
254 .get_mut(&TypeId::of::<V>())
255 .ok_or_else(|| MapError::KeyNotFound(type_name::<V>().to_string()))?;
256
257 // Type is guaranteed to match since TypeId is the key
258 let reference = value.downcast_mut::<V>().unwrap();
259 Ok(f(reference))
260 }
261
262 /// Removes a value by its type.
263 ///
264 /// # Errors
265 ///
266 /// Returns `MapError::LockError` if the internal lock cannot be acquired.
267 ///
268 /// # Returns
269 ///
270 /// Returns `Ok(true)` if a value was removed, `Ok(false)` if no value
271 /// of that type existed.
272 ///
273 /// # Examples
274 ///
275 /// ```
276 /// # use sovran_typemap::{TypeStore, MapError};
277 /// # fn main() -> Result<(), MapError> {
278 /// let store = TypeStore::new();
279 /// store.set(42i32)?;
280 ///
281 /// assert!(store.remove::<i32>()?);
282 /// assert!(!store.remove::<i32>()?); // Already removed
283 /// # Ok(())
284 /// # }
285 /// ```
286 pub fn remove<V: 'static>(&self) -> Result<bool, MapError> {
287 let mut store = self.items.lock().map_err(|_| MapError::LockError)?;
288 Ok(store.remove(&TypeId::of::<V>()).is_some())
289 }
290
291 /// Checks if a value of the given type exists.
292 ///
293 /// # Errors
294 ///
295 /// Returns `MapError::LockError` if the internal lock cannot be acquired.
296 ///
297 /// # Examples
298 ///
299 /// ```
300 /// # use sovran_typemap::{TypeStore, MapError};
301 /// # fn main() -> Result<(), MapError> {
302 /// let store = TypeStore::new();
303 ///
304 /// assert!(!store.contains::<i32>()?);
305 /// store.set(42i32)?;
306 /// assert!(store.contains::<i32>()?);
307 /// # Ok(())
308 /// # }
309 /// ```
310 pub fn contains<V: 'static>(&self) -> Result<bool, MapError> {
311 let store = self.items.lock().map_err(|_| MapError::LockError)?;
312 Ok(store.contains_key(&TypeId::of::<V>()))
313 }
314
315 /// Gets the number of values in the store.
316 ///
317 /// # Errors
318 ///
319 /// Returns `MapError::LockError` if the internal lock cannot be acquired.
320 ///
321 /// # Examples
322 ///
323 /// ```
324 /// # use sovran_typemap::{TypeStore, MapError};
325 /// # fn main() -> Result<(), MapError> {
326 /// let store = TypeStore::new();
327 /// assert_eq!(store.len()?, 0);
328 ///
329 /// store.set(42i32)?;
330 /// store.set("hello".to_string())?;
331 /// assert_eq!(store.len()?, 2);
332 /// # Ok(())
333 /// # }
334 /// ```
335 pub fn len(&self) -> Result<usize, MapError> {
336 let store = self.items.lock().map_err(|_| MapError::LockError)?;
337 Ok(store.len())
338 }
339
340 /// Checks if the store is empty.
341 ///
342 /// # Errors
343 ///
344 /// Returns `MapError::LockError` if the internal lock cannot be acquired.
345 ///
346 /// # Examples
347 ///
348 /// ```
349 /// # use sovran_typemap::{TypeStore, MapError};
350 /// # fn main() -> Result<(), MapError> {
351 /// let store = TypeStore::new();
352 /// assert!(store.is_empty()?);
353 ///
354 /// store.set(42i32)?;
355 /// assert!(!store.is_empty()?);
356 /// # Ok(())
357 /// # }
358 /// ```
359 pub fn is_empty(&self) -> Result<bool, MapError> {
360 let store = self.items.lock().map_err(|_| MapError::LockError)?;
361 Ok(store.is_empty())
362 }
363}
364
365impl Default for TypeStore {
366 fn default() -> Self {
367 Self::new()
368 }
369}
370
371#[cfg(test)]
372mod tests {
373 use super::*;
374
375 #[derive(Clone, Debug, PartialEq)]
376 struct TestConfig {
377 name: String,
378 value: i32,
379 }
380
381 #[derive(Clone, Debug, PartialEq)]
382 struct AnotherConfig {
383 enabled: bool,
384 }
385
386 #[test]
387 fn test_set_and_get() -> Result<(), MapError> {
388 let store = TypeStore::new();
389
390 store.set(TestConfig {
391 name: "test".to_string(),
392 value: 42,
393 })?;
394
395 let config = store.get::<TestConfig>()?;
396 assert_eq!(config.name, "test");
397 assert_eq!(config.value, 42);
398
399 Ok(())
400 }
401
402 #[test]
403 fn test_multiple_types() -> Result<(), MapError> {
404 let store = TypeStore::new();
405
406 store.set(TestConfig {
407 name: "test".to_string(),
408 value: 42,
409 })?;
410 store.set(AnotherConfig { enabled: true })?;
411 store.set(123i32)?;
412 store.set("hello".to_string())?;
413
414 assert_eq!(store.get::<TestConfig>()?.value, 42);
415 assert!(store.get::<AnotherConfig>()?.enabled);
416 assert_eq!(store.get::<i32>()?, 123);
417 assert_eq!(store.get::<String>()?, "hello");
418
419 Ok(())
420 }
421
422 #[test]
423 fn test_overwrite() -> Result<(), MapError> {
424 let store = TypeStore::new();
425
426 store.set(42i32)?;
427 assert_eq!(store.get::<i32>()?, 42);
428
429 store.set(100i32)?;
430 assert_eq!(store.get::<i32>()?, 100);
431
432 // Still only one item
433 assert_eq!(store.len()?, 1);
434
435 Ok(())
436 }
437
438 #[test]
439 fn test_with() -> Result<(), MapError> {
440 let store = TypeStore::new();
441 store.set(vec![1, 2, 3, 4, 5])?;
442
443 let sum = store.with::<Vec<i32>, _, _>(|v| v.iter().sum::<i32>())?;
444 assert_eq!(sum, 15);
445
446 Ok(())
447 }
448
449 #[test]
450 fn test_with_mut() -> Result<(), MapError> {
451 let store = TypeStore::new();
452 store.set(vec![1, 2, 3])?;
453
454 store.with_mut::<Vec<i32>, _, _>(|v| {
455 v.push(4);
456 v.push(5);
457 })?;
458
459 let len = store.with::<Vec<i32>, _, _>(|v| v.len())?;
460 assert_eq!(len, 5);
461
462 Ok(())
463 }
464
465 #[test]
466 fn test_remove() -> Result<(), MapError> {
467 let store = TypeStore::new();
468 store.set(42i32)?;
469
470 assert!(store.contains::<i32>()?);
471 assert!(store.remove::<i32>()?);
472 assert!(!store.contains::<i32>()?);
473 assert!(!store.remove::<i32>()?);
474
475 Ok(())
476 }
477
478 #[test]
479 fn test_contains() -> Result<(), MapError> {
480 let store = TypeStore::new();
481
482 assert!(!store.contains::<i32>()?);
483 store.set(42i32)?;
484 assert!(store.contains::<i32>()?);
485
486 Ok(())
487 }
488
489 #[test]
490 fn test_len_and_is_empty() -> Result<(), MapError> {
491 let store = TypeStore::new();
492
493 assert!(store.is_empty()?);
494 assert_eq!(store.len()?, 0);
495
496 store.set(42i32)?;
497 assert!(!store.is_empty()?);
498 assert_eq!(store.len()?, 1);
499
500 store.set("hello".to_string())?;
501 assert_eq!(store.len()?, 2);
502
503 store.remove::<i32>()?;
504 assert_eq!(store.len()?, 1);
505
506 Ok(())
507 }
508
509 #[test]
510 fn test_key_not_found_error() {
511 let store = TypeStore::new();
512
513 match store.get::<TestConfig>() {
514 Err(MapError::KeyNotFound(type_name)) => {
515 assert!(type_name.contains("TestConfig"));
516 }
517 _ => panic!("Expected KeyNotFound error"),
518 }
519 }
520
521 #[test]
522 fn test_set_with() -> Result<(), MapError> {
523 let store = TypeStore::new();
524
525 store.set_with(|| TestConfig {
526 name: "lazy".to_string(),
527 value: 99,
528 })?;
529
530 let config = store.get::<TestConfig>()?;
531 assert_eq!(config.name, "lazy");
532 assert_eq!(config.value, 99);
533
534 Ok(())
535 }
536
537 #[test]
538 fn test_thread_safety() -> Result<(), MapError> {
539 use std::sync::Arc;
540 use std::thread;
541
542 let store = Arc::new(TypeStore::new());
543 store.set(0i32)?;
544
545 let mut handles = vec![];
546
547 for _ in 0..10 {
548 let store = Arc::clone(&store);
549 handles.push(thread::spawn(move || {
550 for _ in 0..100 {
551 store
552 .with_mut::<i32, _, _>(|v| {
553 *v += 1;
554 })
555 .unwrap();
556 }
557 }));
558 }
559
560 for handle in handles {
561 handle.join().unwrap();
562 }
563
564 assert_eq!(store.get::<i32>()?, 1000);
565
566 Ok(())
567 }
568}