TypeMap

Struct TypeMap 

Source
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>
where K: Clone + Eq + Hash + Debug,

Source

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();
Source

pub fn set<V>(&self, key: K, value: V) -> Result<(), MapError>
where V: 'static + Any + Send + Sync,

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)?;
Source

pub fn set_with<V, F>(&self, key: K, f: F) -> Result<(), MapError>
where V: 'static + Any + Send + Sync, F: FnOnce() -> V,

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),
}
Source

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::LockError if the internal lock cannot be acquired
  • Returns MapError::KeyNotFound if the key doesn’t exist in the store
  • Returns MapError::TypeMismatch if 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),
}
Source

pub fn with<V: 'static, F, R>(&self, key: &K, f: F) -> Result<R, MapError>
where F: FnOnce(&V) -> R,

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::LockError if the internal lock cannot be acquired
  • Returns MapError::KeyNotFound if the key doesn’t exist in the store
  • Returns MapError::TypeMismatch if 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),
}
Source

pub fn with_mut<V: 'static, F, R>(&self, key: &K, f: F) -> Result<R, MapError>
where F: FnOnce(&mut V) -> R,

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::LockError if the internal lock cannot be acquired
  • Returns MapError::KeyNotFound if the key doesn’t exist in the store
  • Returns MapError::TypeMismatch if 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),
}
Source

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),
}
Source

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),
}
Source

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),
}
Source

pub fn values<V>(&self) -> Result<Vec<V>, MapError>
where V: 'static + Clone,

Source

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),
}
Source

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),
}

Trait Implementations§

Source§

impl<K: Clone> Clone for TypeMap<K>

Source§

fn clone(&self) -> TypeMap<K>

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<K: Debug> Debug for TypeMap<K>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl<K> Default for TypeMap<K>
where K: Clone + Eq + Hash + Debug,

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl<K> Freeze for TypeMap<K>

§

impl<K> RefUnwindSafe for TypeMap<K>

§

impl<K> Send for TypeMap<K>
where K: Send,

§

impl<K> Sync for TypeMap<K>
where K: Send,

§

impl<K> Unpin for TypeMap<K>

§

impl<K> UnwindSafe for TypeMap<K>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.