sovran_typemap/
lib.rs

1//! # sovran-typemap
2//!
3//! A thread-safe, type-safe heterogeneous container library for Rust.
4//!
5//! `sovran-typemap` provides a flexible way to store different types in a single
6//! container while maintaining type-safety through runtime checks. This is particularly
7//! useful for applications that need to share state between components without requiring
8//! all components to know about all types.
9//!
10//! ## Key Features
11//!
12//! - **Type-safe**: Values are checked at runtime to ensure type correctness
13//! - **Thread-safe**: Most containers built on `Arc<Mutex<_>>` for safe concurrent access
14//! - **Ergonomic API**: Simple methods with closures for storing, retrieving, and modifying values
15//! - **Multiple Container Types**: Choose the right container for your use case
16//! - **Flexible**: Supports any type that implements `Any + Send + Sync`
17//! - **No macros**: Pure runtime solution without complex macro magic
18//! - **No Unsafe Code**: Relies entirely on safe Rust
19//!
20//! ## Container Types
21//!
22//! | Type | Key | Thread-Safe | Cloneable | Use Case |
23//! |------|-----|-------------|-----------|----------|
24//! | [`TypeMap<K>`] | Any hashable type | ✅ | ❌ | General-purpose storage with explicit keys |
25//! | [`TypeStore`] | Type itself | ✅ | ❌ | Service locator / DI container |
26//! | [`TypeStoreValue`] | Type itself | ❌ | ✅ | Cloneable state, single-threaded contexts |
27//! | [`TraitTypeMap<K>`] | Any hashable type | ✅ | ❌ | Polymorphic access via trait interfaces |
28//!
29//! ## Quick Examples
30//!
31//! ### TypeMap: Keyed Heterogeneous Storage
32//!
33//! ```rust
34//! use sovran_typemap::{TypeMap, MapError};
35//!
36//! fn main() -> Result<(), MapError> {
37//!     let store = TypeMap::<String>::new();
38//!
39//!     store.set("number".to_string(), 42i32)?;
40//!     store.set("text".to_string(), "Hello!".to_string())?;
41//!
42//!     let num = store.get::<i32>(&"number".to_string())?;
43//!     println!("Number: {}", num);
44//!
45//!     Ok(())
46//! }
47//! ```
48//!
49//! ### TypeStore: Type-Keyed Storage (DI Container)
50//!
51//! ```rust
52//! use sovran_typemap::{TypeStore, MapError};
53//!
54//! #[derive(Clone, Debug)]
55//! struct DatabaseConfig { host: String, port: u16 }
56//!
57//! fn main() -> Result<(), MapError> {
58//!     let store = TypeStore::new();
59//!
60//!     // Type IS the key - no string keys needed
61//!     store.set(DatabaseConfig {
62//!         host: "localhost".to_string(),
63//!         port: 5432,
64//!     })?;
65//!
66//!     let config = store.get::<DatabaseConfig>()?;
67//!     println!("Database: {}:{}", config.host, config.port);
68//!
69//!     Ok(())
70//! }
71//! ```
72//!
73//! ### TypeStoreValue: Cloneable Type-Keyed Storage
74//!
75//! ```rust
76//! use sovran_typemap::TypeStoreValue;
77//!
78//! #[derive(Clone, Debug)]
79//! struct GameState { level: u32, score: u64 }
80//!
81//! fn main() -> Result<(), ()> {
82//!     let mut state = TypeStoreValue::new();
83//!     state.set(GameState { level: 1, score: 0 });
84//!
85//!     // Take a snapshot
86//!     let snapshot = state.clone();
87//!
88//!     // Modify original
89//!     state.with_mut::<GameState, _, _>(|gs| gs.level = 2);
90//!
91//!     // Snapshot unchanged
92//!     assert_eq!(snapshot.get::<GameState>().unwrap().level, 1);
93//!     assert_eq!(state.get::<GameState>().unwrap().level, 2);
94//!
95//!     Ok(())
96//! }
97//! ```
98//!
99//! ### TraitTypeMap: Polymorphic Access
100//!
101//! ```rust
102//! use sovran_typemap::{TraitTypeMap, MapError};
103//! use std::any::Any;
104//!
105//! trait Greeter: Any + Send + Sync {
106//!     fn greet(&self) -> String;
107//! }
108//!
109//! #[derive(Clone)]
110//! struct English { name: String }
111//!
112//! impl Greeter for English {
113//!     fn greet(&self) -> String { format!("Hello, {}!", self.name) }
114//! }
115//!
116//! impl Into<Box<dyn Greeter>> for English {
117//!     fn into(self) -> Box<dyn Greeter> { Box::new(self) }
118//! }
119//!
120//! fn main() -> Result<(), MapError> {
121//!     let store = TraitTypeMap::<String>::new();
122//!
123//!     store.set_trait::<dyn Greeter, _>(
124//!         "greeter".to_string(),
125//!         English { name: "World".to_string() }
126//!     )?;
127//!
128//!     // Access via trait interface
129//!     store.with_trait::<dyn Greeter, _, _>(&"greeter".to_string(), |g| {
130//!         println!("{}", g.greet());
131//!     })?;
132//!
133//!     Ok(())
134//! }
135//! ```
136
137mod any_value;
138mod error;
139mod map;
140mod store;
141mod store_value;
142mod traits;
143
144pub use error::MapError;
145pub use map::TypeMap;
146pub use store::TypeStore;
147pub use store_value::{CloneAny, TypeStoreValue};
148pub use traits::TraitTypeMap;
149
150// Re-export std::any for convenience
151pub use std::any::{Any, TypeId};