pub struct FastSingletonCache { /* private fields */ }Expand description
Fast singleton cache using OnceCell for zero-overhead repeated access.
This cache provides near-zero overhead singleton resolution after the first access. It uses OnceCell internally to ensure thread-safe lazy initialization with optimal performance characteristics.
§Performance Characteristics
- First access: Full factory execution + registration overhead
- Subsequent access: Single atomic load (OnceCell optimizes to plain load)
- Concurrent access: Lock-free reads, minimal contention on writes
- Memory overhead: ~8 bytes per singleton + value size
§Sharding Strategy
The cache is sharded by TypeId hash to reduce contention when multiple threads are initializing different singletons concurrently. Each shard has its own lock.
§Examples
use ferrous_di::{ServiceCollection, Resolver};
use std::sync::Arc;
struct ExpensiveService {
data: Vec<u8>,
}
impl ExpensiveService {
fn new() -> Self {
// Expensive initialization
Self { data: vec![1, 2, 3, 4, 5] }
}
}
// Register as singleton - automatically uses FastSingletonCache optimization
let mut services = ServiceCollection::new();
services.add_singleton(ExpensiveService::new());
let provider = services.build();
// First access - runs factory once, cached with OnceCell
let service1 = provider.get_required::<ExpensiveService>();
// Subsequent accesses - ultra-fast cached retrieval (~31ns)
let service2 = provider.get_required::<ExpensiveService>();
assert!(Arc::ptr_eq(&service1, &service2));Implementations§
Source§impl FastSingletonCache
impl FastSingletonCache
Sourcepub fn get_or_init<F>(
&self,
key: &Key,
factory: F,
) -> Arc<dyn Any + Send + Sync>
pub fn get_or_init<F>( &self, key: &Key, factory: F, ) -> Arc<dyn Any + Send + Sync>
Gets or initializes a singleton with the given factory.
This method provides optimal performance for repeated access to the same singleton. The factory is only called once, and subsequent calls return the cached value with minimal overhead.
§Performance Notes
- Thread Safety: Multiple threads can safely call this concurrently
- Initialization: Only one thread will execute the factory function
- Subsequent Access: Near-zero overhead after initialization
§Examples
use ferrous_di::{ServiceCollection, Resolver};
use std::sync::Arc;
struct DatabaseService {
connection_pool: Vec<String>,
}
impl DatabaseService {
fn new() -> Self {
// Expensive initialization
Self {
connection_pool: vec!["conn1".to_string(), "conn2".to_string()],
}
}
}
// The ServiceProvider automatically uses embedded OnceCell optimization for singletons
let mut services = ServiceCollection::new();
services.add_singleton_factory::<DatabaseService, _>(|_| DatabaseService::new());
let provider = services.build();
// First access - runs factory once
let db1 = provider.get_required::<DatabaseService>();
// Subsequent accesses - ultra-fast path (world-class 31ns performance)
for _ in 0..1000 {
let db_same = provider.get_required::<DatabaseService>();
assert!(Arc::ptr_eq(&db1, &db_same));
}Sourcepub fn get(&self, key: &Key) -> Option<Arc<dyn Any + Send + Sync>>
pub fn get(&self, key: &Key) -> Option<Arc<dyn Any + Send + Sync>>
Gets an existing singleton without initializing.
Returns None if the singleton hasn’t been initialized yet.
This is useful for checking if a singleton exists without triggering creation.