sovran-typemap
A thread-safe, type-safe heterogeneous container library for Rust.
sovran-typemap provides a flexible way to store different types in a single container while maintaining type-safety through runtime checks. This is particularly useful for applications that need to share state between components without requiring all components to know about all types.
Key Features
- Type-safe: Values are checked at runtime to ensure type correctness
- Thread-safe: Built on
Arc<Mutex<_>>for safe concurrent access - Ergonomic API: Simple methods with closures for storing, retrieving, and modifying values
- Multiple Container Types: Choose the right container for your use case
- Flexible: Supports any type that implements
Any + Send + Syncwith any hashable key type - Comprehensive Error Handling: Detailed error types for better debugging and recovery
- No macros: Pure runtime solution without complex macro magic
- No Unsafe Code: Relies entirely on safe Rust with no
unsafeblocks
Container Types
| Type | Key | Thread-Safe | Cloneable | Use Case |
|---|---|---|---|---|
TypeMap<K> |
Any hashable type | ✅ | ❌ | General-purpose storage with explicit keys |
TypeStore |
Type itself | ✅ | ❌ | Service locator / DI container (one value per type) |
TypeStoreValue |
Type itself | ❌ | ✅ | Cloneable state snapshots, single-threaded contexts |
TraitTypeMap<K> |
Any hashable type | ✅ | ❌ | Polymorphic access via trait interfaces |
Installation
Add this to your Cargo.toml:
[]
= "0.4"
TypeMap: Keyed Heterogeneous Storage
TypeMap stores values with explicit keys, allowing multiple values of the same type under different keys.
use ;
Modifying Values In-Place
use ;
use HashMap;
TypeStore: Type-Keyed Storage
TypeStore uses the type itself as the key, storing exactly one value per type. Perfect for dependency injection and service locator patterns.
use ;
Service Locator Pattern
use ;
use Arc;
TypeStoreValue: Cloneable Type-Keyed Storage
TypeStoreValue is like TypeStore but without the Arc<Mutex<>> wrapper, making it cloneable. Useful for state snapshots or single-threaded contexts.
use TypeStoreValue;
Note: TypeStoreValue requires stored types to implement Clone. The API returns Option instead of Result since there's no lock that can fail.
TraitTypeMap: Polymorphic Access
TraitTypeMap lets you store values and access them either by concrete type or through a trait interface:
use ;
use Any;
// Define a trait (must be Any + Send + Sync)
// Required: implement Into<Box<dyn Trait>> for your type
Choosing a Container
-
TypeMap<K>: When you need multiple values of the same type with different keys. General-purpose heterogeneous storage. -
TypeStore: When type uniquely identifies the value and you need thread-safety. Dependency injection, configuration objects, service locators. -
TypeStoreValue: When type uniquely identifies the value but you need cloneability over thread-safety. State snapshots, undo systems, single-threaded contexts. -
TraitTypeMap<K>: When you need polymorphic access through trait interfaces, or want to iterate over values through a common trait.
Sharing State Between Components
use ;
use Arc;
Error Handling
use ;
API Reference
TypeMap
| Method | Description |
|---|---|
new() |
Create a new empty TypeMap |
set(key, value) |
Store a value with a key |
set_with(key, closure) |
Store a value generated by a closure |
get<T>(key) |
Get a clone of a value |
with<T, F, R>(key, closure) |
Access a value with a read-only closure |
with_mut<T, F, R>(key, closure) |
Access a value with a read-write closure |
remove(key) |
Remove a value |
contains_key(key) |
Check if a key exists |
keys() |
Get all keys |
values<T>() |
Get all values of a specific type |
len() |
Get the number of items |
is_empty() |
Check if the store is empty |
TypeStore
| Method | Description |
|---|---|
new() |
Create a new empty TypeStore |
set(value) |
Store a value (type is the key) |
set_with(closure) |
Store a value generated by a closure |
get<T>() |
Get a clone of a value by type |
with<T, F, R>(closure) |
Access a value with a read-only closure |
with_mut<T, F, R>(closure) |
Access a value with a read-write closure |
remove<T>() |
Remove a value by type |
contains<T>() |
Check if a type exists |
len() |
Get the number of items |
is_empty() |
Check if the store is empty |
TypeStoreValue
| Method | Description |
|---|---|
new() |
Create a new empty TypeStoreValue |
set(value) |
Store a value (type is the key) |
set_with(closure) |
Store a value generated by a closure |
get<T>() |
Get a clone of a value by type (Option) |
with<T, F, R>(closure) |
Access a value with a read-only closure (Option) |
with_mut<T, F, R>(closure) |
Access a value with a read-write closure (Option) |
remove<T>() |
Remove a value by type |
contains<T>() |
Check if a type exists |
len() |
Get the number of items |
is_empty() |
Check if the store is empty |
clone() |
Clone the entire store |
TraitTypeMap
| Method | Description |
|---|---|
new() |
Create a new empty TraitTypeMap |
set_trait<T, U>(key, value) |
Store a value with its trait type |
with<T, F, R>(key, closure) |
Access by concrete type (read-only) |
with_mut<T, F, R>(key, closure) |
Access by concrete type (read-write) |
with_trait<T, F, R>(key, closure) |
Access through trait interface |
remove(key) |
Remove a value |
contains_key(key) |
Check if a key exists |
keys() |
Get all keys |
len() |
Get the number of items |
is_empty() |
Check if the store is empty |
License
This project is licensed under the MIT License - see the LICENSE file for details.
Contribution
Contributions are welcome! Please feel free to submit a Pull Request.