Extensions

Struct Extensions 

Source
pub struct Extensions {
    pub map: Arc<DashMap<TypeId, Arc<dyn Any + Send + Sync>>>,
}
Expand description

A thread-safe type map for storing arbitrary extensions.

Extensions provides a way to store heterogeneous data in a type-safe manner. It uses Rust’s type system to ensure that data can only be retrieved with the correct type, preventing runtime type errors.

§Thread Safety

This type is thread-safe and can be safely shared across threads. All operations use appropriate locking to ensure data consistency.

§Type Storage

Extensions are stored using their TypeId as the key, which means:

  • Each type can only have one instance stored at a time
  • Generic types with different parameters are considered different types
  • Type aliases refer to the same underlying type

§Examples

§Basic Storage and Retrieval

use ignitia::Extensions;

#[derive(Clone, Debug, PartialEq)]
struct UserId(u64);

#[derive(Clone, Debug)]
struct UserName(String);

let mut extensions = Extensions::new();

// Store different types
extensions.insert(UserId(42));
extensions.insert(UserName("Alice".to_string()));

// Retrieve with type safety
let user_id = extensions.get::<UserId>().unwrap();
assert_eq!(user_id.0, 42);

let user_name = extensions.get::<UserName>().unwrap();
assert_eq!(user_name.0, "Alice");

§Working with Optional Data

use ignitia::Extensions;

#[derive(Clone)]
struct OptionalData(String);

let extensions = Extensions::new();

// Safe handling of missing data
match extensions.get::<OptionalData>() {
    Some(data) => println!("Found: {}", data.0),
    None => println!("Data not found"),
}

§Using Arc for Expensive Types

use ignitia::Extensions;
use std::sync::Arc;

#[derive(Debug)]
struct ExpensiveData {
    large_vector: Vec<u8>,
}

let mut extensions = Extensions::new();

// Store as Arc to avoid expensive clones
let expensive_data = Arc::new(ExpensiveData {
    large_vector: vec![0; 1000000],
});
extensions.insert(expensive_data);

// Retrieval returns Arc<Arc<ExpensiveData>>, clone is cheap
if let Some(data) = extensions.get::<Arc<ExpensiveData>>() {
    println!("Data length: {}", data.large_vector.len());
}

Fields§

§map: Arc<DashMap<TypeId, Arc<dyn Any + Send + Sync>>>

Map of extensions.

Implementations§

Source§

impl Extensions

Source

pub fn new() -> Self

Creates a new empty Extensions map.

The map starts with no stored extensions and allocates memory as needed.

§Examples
use ignitia::Extensions;

let extensions = Extensions::new();
assert!(extensions.is_empty());
assert_eq!(extensions.len(), 0);
Source

pub fn insert<T: Send + Sync + 'static>(&mut self, value: T)

Inserts a value into the extensions map.

If a value of the same type was already present, it will be replaced and the old value will be dropped.

§Type Requirements
  • T: Send + Sync + 'static: The type must be thread-safe and have static lifetime
§Parameters
  • value: The value to store in the extensions map
§Examples
use ignitia::Extensions;

#[derive(Clone, Debug, PartialEq)]
struct Config {
    debug: bool,
    timeout: u64,
}

let mut extensions = Extensions::new();
let config = Config { debug: true, timeout: 30 };

extensions.insert(config.clone());
assert_eq!(extensions.len(), 1);

// Inserting the same type replaces the old value
let new_config = Config { debug: false, timeout: 60 };
extensions.insert(new_config.clone());
assert_eq!(extensions.len(), 1);

let retrieved = extensions.get::<Config>().unwrap();
assert_eq!(retrieved.timeout, 60);
§Thread Safety

This method acquires a write lock on the internal map, so it may block if other threads are currently reading or writing.

Source

pub fn get<T>(&self) -> Option<Arc<T>>
where T: Clone + Send + Sync + 'static,

Gets a reference to a value from the extensions map.

This method returns an Arc<T> for shared ownership of the retrieved value. The value is cloned from the stored instance, so the original type must implement Clone.

§Type Requirements
  • T: Send + Sync + 'static + Clone: The type must be thread-safe, have static lifetime, and be cloneable
§Returns
  • Some(Arc<T>) if a value of type T exists
  • None if no value of type T is stored
§Examples
use ignitia::Extensions;

#[derive(Clone, Debug, PartialEq)]
struct DatabaseUrl(String);

let mut extensions = Extensions::new();
let db_url = DatabaseUrl("postgresql://localhost/mydb".to_string());
extensions.insert(db_url);

// Successful retrieval
let retrieved = extensions.get::<DatabaseUrl>().unwrap();
assert_eq!(retrieved.0, "postgresql://localhost/mydb");

// Type safety - different type returns None
#[derive(Clone)]
struct ApiKey(String);
assert!(extensions.get::<ApiKey>().is_none());
§Performance

This method acquires a read lock and performs a hash map lookup by TypeId. The lookup is O(1) on average, but the clone operation depends on the complexity of the stored type.

Source

pub fn remove<T: Send + Sync + 'static>(&mut self) -> Option<T>

Removes a value from the extensions map.

This method takes ownership of the stored value and returns it if it exists. After removal, subsequent calls to get() or contains() for this type will return None/false until a new value is inserted.

§Type Requirements
  • T: Send + Sync + 'static: The type must be thread-safe and have static lifetime
§Returns
  • Some(T) if a value of type T existed and was removed
  • None if no value of type T was stored
§Examples
use ignitia::Extensions;

#[derive(Clone, Debug, PartialEq)]
struct SessionId(String);

let mut extensions = Extensions::new();
let session_id = SessionId("sess_123".to_string());
extensions.insert(session_id.clone());

assert!(extensions.contains::<SessionId>());

// Remove the value
let removed = extensions.remove::<SessionId>().unwrap();
assert_eq!(removed.0, "sess_123");

// Value is no longer present
assert!(!extensions.contains::<SessionId>());
assert!(extensions.get::<SessionId>().is_none());
§Thread Safety

This method acquires a write lock on the internal map, so it may block if other threads are currently reading or writing.

Source

pub fn contains<T: Send + Sync + 'static>(&self) -> bool

Checks if the extensions map contains a value of the specified type.

This is a more efficient alternative to get().is_some() when you only need to check for presence without retrieving the value.

§Type Requirements
  • T: Send + Sync + 'static: The type must be thread-safe and have static lifetime
§Returns
  • true if a value of type T is stored
  • false if no value of type T is stored
§Examples
use ignitia::Extensions;

#[derive(Clone)]
struct Feature1Enabled(bool);

#[derive(Clone)]
struct Feature2Enabled(bool);

let mut extensions = Extensions::new();
extensions.insert(Feature1Enabled(true));

assert!(extensions.contains::<Feature1Enabled>());
assert!(!extensions.contains::<Feature2Enabled>());

// Conditional logic based on presence
if extensions.contains::<Feature1Enabled>() {
    println!("Feature 1 is configured");
}
§Performance

This method only requires a read lock and performs a simple hash map key existence check, making it more efficient than get() when you don’t need the actual value.

Source

pub fn insert_with_typeid( &mut self, type_id: TypeId, value: Arc<dyn Any + Send + Sync>, ) -> Option<Arc<dyn Any + Send + Sync>>

Insert a value with explicit TypeId, returns the old value if it existed

Source

pub fn contains_typeid(&self, type_id: TypeId) -> bool

Check if a TypeId already exists in extensions

Source

pub fn insert_if_not_exists_typeid( &mut self, type_id: TypeId, value: Arc<dyn Any + Send + Sync>, ) -> bool

Insert only if TypeId doesn’t already exist, returns true if inserted, false if already exists

Source

pub fn get_by_typeid( &self, type_id: TypeId, ) -> Option<Ref<'_, TypeId, Arc<dyn Any + Send + Sync>>>

Get a value by TypeId without type checking - returns raw boxed value

Source

pub fn remove_by_typeid( &mut self, type_id: TypeId, ) -> Option<Arc<dyn Any + Send + Sync>>

Remove a value by TypeId

Source

pub fn len(&self) -> usize

Returns the number of extensions stored in the map.

This counts the number of different types stored, not the total memory usage or the number of values within each type.

§Examples
use ignitia::Extensions;

#[derive(Clone)]
struct TypeA(i32);

#[derive(Clone)]
struct TypeB(String);

let mut extensions = Extensions::new();
assert_eq!(extensions.len(), 0);

extensions.insert(TypeA(42));
assert_eq!(extensions.len(), 1);

extensions.insert(TypeB("hello".to_string()));
assert_eq!(extensions.len(), 2);

// Inserting the same type again doesn't increase count
extensions.insert(TypeA(100));
assert_eq!(extensions.len(), 2);
§Performance

This operation requires a read lock and calls HashMap::len(), which is O(1).

Source

pub fn is_empty(&self) -> bool

Checks if the extensions map is empty.

Returns true if no extensions are stored, false otherwise.

§Examples
use ignitia::Extensions;

#[derive(Clone)]
struct SomeData(String);

let mut extensions = Extensions::new();
assert!(extensions.is_empty());

extensions.insert(SomeData("test".to_string()));
assert!(!extensions.is_empty());

extensions.remove::<SomeData>();
assert!(extensions.is_empty());
§Performance

This is equivalent to self.len() == 0 but may be slightly more efficient depending on the HashMap implementation.

Source

pub fn clear(&mut self)

Clears all extensions from the map.

After calling this method, the map will be empty and all stored extensions will be dropped.

§Examples
use ignitia::Extensions;

#[derive(Clone)]
struct Data1(i32);

#[derive(Clone)]
struct Data2(String);

let mut extensions = Extensions::new();
extensions.insert(Data1(42));
extensions.insert(Data2("hello".to_string()));

assert_eq!(extensions.len(), 2);

extensions.clear();
assert!(extensions.is_empty());
assert!(!extensions.contains::<Data1>());
assert!(!extensions.contains::<Data2>());
§Thread Safety

This method acquires a write lock on the internal map. All stored values will be dropped while holding the lock.

Trait Implementations§

Source§

impl Clone for Extensions

Source§

fn clone(&self) -> Extensions

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 Debug for Extensions

Source§

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

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

impl Default for Extensions

Source§

fn default() -> Extensions

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

Auto Trait Implementations§

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> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
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> Same for T

Source§

type Output = T

Should always be Self
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.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

impl<T> ErasedDestructor for T
where T: 'static,