pub struct TypeMap<K> { /* private fields */ }Expand description
A thread-safe heterogeneous container with type-safety
TypeMap allows you to store values of different types in a single container
while maintaining type-safety through runtime checks. It provides a convenient way
to share state between components without requiring all components to know about all types.
§Examples
use sovran_typemap::{TypeMap, MapError};
fn main() -> Result<(), MapError> {
// Create a new TypeMap with string keys
let store = TypeMap::<String>::new();
// Store values of different types
store.set("number".to_string(), 42i32)?;
store.set("text".to_string(), "Hello, world!".to_string())?;
store.set("flags".to_string(), vec![true, false, true])?;
// Retrieve values with type safety
let num = store.get::<i32>(&"number".to_string())?;
println!("Retrieved: {}", num);
// Use with_mut to modify values in place
store.with_mut::<Vec<bool>, _, _>(&"flags".to_string(), |flags| {
flags.push(true);
println!("Updated flags: {:?}", flags);
})?;
Ok(())
}Implementations§
Source§impl<K> TypeMap<K>
impl<K> TypeMap<K>
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new, empty TypeMap
§Examples
use sovran_typemap::TypeMap;
// Create a TypeMap with String keys
let string_store = TypeMap::<String>::new();
// Create a TypeMap with numeric keys
let int_store = TypeMap::<u32>::new();Sourcepub fn set<V>(&self, key: K, value: V) -> Result<(), MapError>
pub fn set<V>(&self, key: K, value: V) -> Result<(), MapError>
Stores a value of any type that implements Any, Send, and Sync
§Errors
Returns MapError::LockError if the internal lock cannot be acquired.
§Examples
let store: TypeMap<String> = TypeMap::new();
// Store values of different types
store.set("number".to_string(), 42i32)?;
store.set("text".to_string(), "Hello, world!".to_string())?;
store.set("complex".to_string(), (1, "tuple", true))?;
// Overwrite an existing value
store.set("number".to_string(), 100i32)?;Sourcepub fn set_with<V, F>(&self, key: K, f: F) -> Result<(), MapError>
pub fn set_with<V, F>(&self, key: K, f: F) -> Result<(), MapError>
Stores a value generated by a closure
This is useful for lazy initialization or complex value construction where you want to avoid creating the value if the lock can’t be acquired.
§Errors
Returns MapError::LockError if the internal lock cannot be acquired.
§Examples
let store: TypeMap<String> = TypeMap::new();
// Lazily construct a complex value
store.set_with("user_data".to_string(), || {
// Imagine this is an expensive operation
let mut data = Vec::new();
for i in 0..1000 {
data.push(i * 2);
}
data
})?;
// Access the constructed data
store.with(&"user_data".to_string(), |data: &Vec<i32>| {
println!("First value: {}", data.first().unwrap_or(&0));
})?;Handling potential errors:
let store: TypeMap<String> = TypeMap::new();
// Handle potential errors from set_with
match store.set_with("config".to_string(), || {
// In a real scenario, this might load from a file
std::collections::HashMap::<String, String>::new()
}) {
Ok(()) => println!("Configuration stored successfully"),
Err(MapError::LockError) => eprintln!("Failed to acquire lock - try again later"),
Err(e) => eprintln!("Unexpected error: {}", e),
}Sourcepub fn get<V>(&self, key: &K) -> Result<V, MapError>where
V: 'static + Clone,
pub fn get<V>(&self, key: &K) -> Result<V, MapError>where
V: 'static + Clone,
Retrieves a clone of a value from the store
This provides a convenient way to get a copy of a value when the Clone
trait is available. For more complex operations or to avoid cloning,
use with instead.
§Type Parameters
V- The type of the value to retrieve. Must match the type that was stored.
§Errors
- Returns
MapError::LockErrorif the internal lock cannot be acquired - Returns
MapError::KeyNotFoundif the key doesn’t exist in the store - Returns
MapError::TypeMismatchif the value exists but has a different type
§Examples
let store: TypeMap<String> = TypeMap::new();
store.set("answer".to_string(), 42i32)?;
// Get a clone of the value
let value = store.get::<i32>(&"answer".to_string())?;
assert_eq!(value, 42);
// Handle possible errors
match store.get::<String>(&"non_existent".to_string()) {
Ok(value) => println!("Value: {}", value),
Err(MapError::KeyNotFound(key)) => println!("Key not found {}", key),
Err(MapError::TypeMismatch) => println!("Type mismatch"),
Err(MapError::LockError) => println!("Failed to acquire lock"),
}
// Type mismatch example
store.set("name".to_string(), "Alice".to_string())?;
match store.get::<i32>(&"name".to_string()) {
Ok(value) => println!("Value: {}", value),
Err(MapError::TypeMismatch) => println!("The value is not an i32"),
Err(e) => println!("Other error: {}", e),
}Sourcepub fn with<V: 'static, F, R>(&self, key: &K, f: F) -> Result<R, MapError>
pub fn with<V: 'static, F, R>(&self, key: &K, f: F) -> Result<R, MapError>
Gets a value by executing a closure with read access
This method allows for arbitrary operations on the stored value without
requiring the value to implement Clone. It’s useful for inspecting values,
computing derived values, or performing operations that don’t require ownership.
§Type Parameters
V- The type of the value to access. Must match the type that was stored.F- A closure that takes a reference to the value and returns a result.R- The return type of the closure.
§Errors
- Returns
MapError::LockErrorif the internal lock cannot be acquired - Returns
MapError::KeyNotFoundif the key doesn’t exist in the store - Returns
MapError::TypeMismatchif the value exists but has a different type
§Examples
let store: TypeMap<String> = TypeMap::new();
store.set("users".to_string(), vec!["Alice", "Bob", "Charlie"])?;
// Read and compute something from the value
let user_count = store.with(&"users".to_string(), |users: &Vec<&str>| users.len())?;
println!("Number of users: {}", user_count);
// Checking if a specific value exists
let has_alice = store.with(&"users".to_string(), |users: &Vec<&str>| {
users.contains(&"Alice")
})?;
// Handle potential errors with pattern matching
match store.with(&"settings".to_string(), |settings: &std::collections::HashMap<String, String>| {
settings.get("theme").cloned()
}) {
Ok(Some(theme)) => println!("Current theme: {}", theme),
Ok(None) => println!("Theme setting not found"),
Err(MapError::KeyNotFound(_)) => println!("Settings not initialized"),
Err(MapError::TypeMismatch) => println!("Settings has unexpected type"),
Err(e) => println!("Error: {}", e),
}Sourcepub fn with_mut<V: 'static, F, R>(&self, key: &K, f: F) -> Result<R, MapError>
pub fn with_mut<V: 'static, F, R>(&self, key: &K, f: F) -> Result<R, MapError>
Gets a value by executing a closure with write access
This method allows for modifying the stored value in place without replacing it entirely. It’s useful for updating collections or complex structures.
§Type Parameters
V- The type of the value to access. Must match the type that was stored.F- A closure that takes a mutable reference to the value and returns a result.R- The return type of the closure.
§Errors
- Returns
MapError::LockErrorif the internal lock cannot be acquired - Returns
MapError::KeyNotFoundif the key doesn’t exist in the store - Returns
MapError::TypeMismatchif the value exists but has a different type
§Examples
let store: TypeMap<String> = TypeMap::new();
// Initialize a vector
store.set("numbers".to_string(), vec![1, 2, 3])?;
// Modify the vector in place
store.with_mut(&"numbers".to_string(), |numbers: &mut Vec<i32>| {
numbers.push(4);
numbers.push(5);
})?;
// Verify the modification
let count = store.with(&"numbers".to_string(), |numbers: &Vec<i32>| {
assert_eq!(numbers, &[1, 2, 3, 4, 5]);
numbers.len()
})?;
println!("Vector now has {} elements", count);
// Example with a HashMap
store.set("counters".to_string(), std::collections::HashMap::<String, i32>::new())?;
// Update counter values
let result = store.with_mut(&"counters".to_string(), |counters: &mut std::collections::HashMap<String, i32>| {
*counters.entry("visits".to_string()).or_insert(0) += 1;
counters.get("visits").copied() // Return current count
})?;
println!("Visit count: {}", result.unwrap_or(0));
// Error handling example
match store.with_mut(&"config".to_string(), |config: &mut std::collections::HashMap<String, String>| {
config.insert("theme".to_string(), "dark".to_string())
}) {
Ok(old_theme) => println!("Previous theme: {:?}", old_theme),
Err(MapError::KeyNotFound(_)) => println!("Config not found"),
Err(MapError::TypeMismatch) => println!("Config has wrong type"),
Err(e) => println!("Error: {}", e),
}Sourcepub fn remove(&self, key: &K) -> Result<bool, MapError>
pub fn remove(&self, key: &K) -> Result<bool, MapError>
Removes a value from the store
§Errors
Returns MapError::LockError if the internal lock cannot be acquired.
§Returns
Returns Ok(true) if the key was present and the value was removed.
Returns Ok(false) if the key was not present.
§Examples
let store: TypeMap<String> = TypeMap::new();
store.set("temp".to_string(), "This is temporary".to_string())?;
// Remove the value
let was_removed = store.remove(&"temp".to_string())?;
assert!(was_removed);
// Check that it's gone
match store.get::<String>(&"temp".to_string()) {
Err(MapError::KeyNotFound(key)) => println!("Key `{}` was successfully removed", key),
Ok(_) => println!("Key still exists"),
Err(e) => println!("Error: {}", e),
}
// Removing a non-existent key
let was_removed = store.remove(&"nonexistent".to_string())?;
assert!(!was_removed);
// Using pattern matching for error handling
match store.remove(&"another_key".to_string()) {
Ok(true) => println!("Key was found and removed"),
Ok(false) => println!("Key did not exist"),
Err(MapError::LockError) => println!("Failed to acquire lock"),
Err(e) => println!("Unexpected error: {}", e),
}Sourcepub fn contains_key(&self, key: &K) -> Result<bool, MapError>
pub fn contains_key(&self, key: &K) -> Result<bool, MapError>
Checks if a key exists in the store
This method only checks for the existence of the key and does not validate the type of the stored value.
§Errors
Returns MapError::LockError if the internal lock cannot be acquired.
§Examples
let store: TypeMap<String> = TypeMap::new();
store.set("config".to_string(), std::collections::HashMap::<String, String>::new())?;
// Check if a key exists
let has_config = store.contains_key(&"config".to_string())?;
assert!(has_config);
let has_users = store.contains_key(&"users".to_string())?;
assert!(!has_users);
// Use in conditional logic
if !store.contains_key(&"initialized".to_string())? {
store.set("initialized".to_string(), true)?;
println!("Store initialized for the first time");
}
// Error handling
match store.contains_key(&"settings".to_string()) {
Ok(true) => println!("Settings exist"),
Ok(false) => println!("Settings do not exist"),
Err(e) => println!("Error checking settings: {}", e),
}Sourcepub fn keys(&self) -> Result<Vec<K>, MapError>where
K: Clone,
pub fn keys(&self) -> Result<Vec<K>, MapError>where
K: Clone,
Gets all keys in the store
§Errors
Returns MapError::LockError if the internal lock cannot be acquired.
§Examples
let store: TypeMap<String> = TypeMap::new();
store.set("user".to_string(), "Alice".to_string())?;
store.set("count".to_string(), 42i32)?;
store.set("active".to_string(), true)?;
// Get all keys
let keys = store.keys()?;
// Keys are returned in arbitrary order, so sort for stable testing
let mut sorted_keys = keys.clone();
sorted_keys.sort();
assert_eq!(sorted_keys, vec!["active".to_string(), "count".to_string(), "user".to_string()]);
println!("Store contains {} keys", keys.len());
// Use keys to iterate over stored values
for key in keys {
// We need to handle different types differently
if let Ok(value) = store.get::<String>(&key) {
println!("{}: String = {}", key, value);
} else if let Ok(value) = store.get::<i32>(&key) {
println!("{}: i32 = {}", key, value);
} else if let Ok(value) = store.get::<bool>(&key) {
println!("{}: bool = {}", key, value);
} else {
println!("{}: unknown type", key);
}
}
// Error handling
match store.keys() {
Ok(keys) => println!("Found {} keys", keys.len()),
Err(MapError::LockError) => println!("Failed to acquire lock"),
Err(e) => println!("Unexpected error: {}", e),
}pub fn values<V>(&self) -> Result<Vec<V>, MapError>where
V: 'static + Clone,
Sourcepub fn len(&self) -> Result<usize, MapError>
pub fn len(&self) -> Result<usize, MapError>
Gets the number of items in the store
§Errors
Returns MapError::LockError if the internal lock cannot be acquired.
§Examples
let store: TypeMap<String> = TypeMap::new();
// Initially empty
assert_eq!(store.len()?, 0);
// Add some items
store.set("one".to_string(), 1)?;
store.set("two".to_string(), 2)?;
// Check the count
assert_eq!(store.len()?, 2);
// Use in conditional logic
if store.len()? > 10 {
println!("Store has many items");
} else {
println!("Store has few items");
}
// Error handling
match store.len() {
Ok(count) => println!("Store contains {} items", count),
Err(MapError::LockError) => println!("Failed to acquire lock"),
Err(e) => println!("Unexpected error: {}", e),
}Sourcepub fn is_empty(&self) -> Result<bool, MapError>
pub fn is_empty(&self) -> Result<bool, MapError>
Checks if the store is empty
§Errors
Returns MapError::LockError if the internal lock cannot be acquired.
§Examples
let store: TypeMap<String> = TypeMap::new();
// New store is empty
assert!(store.is_empty()?);
// Add an item
store.set("key".to_string(), "value".to_string())?;
// Now it's not empty
assert!(!store.is_empty()?);
// Use in conditional logic
if store.is_empty()? {
println!("Store is empty");
} else {
println!("Store contains items");
}
// Error handling
match store.is_empty() {
Ok(true) => println!("Store is empty"),
Ok(false) => println!("Store has items"),
Err(MapError::LockError) => println!("Failed to acquire lock"),
Err(e) => println!("Unexpected error: {}", e),
}