Crates.io | ferrous-di |
lib.rs | ferrous-di |
version | 0.2.0 |
created_at | 2025-08-21 00:51:40.657762+00 |
updated_at | 2025-08-21 17:02:56.761118+00 |
description | Type-safe, performant dependency injection for Rust, inspired by Microsoft.Extensions.DependencyInjection |
homepage | |
repository | https://github.com/s1ntropy/ferrous-di |
max_upload_size | |
id | 1804146 |
size | 2,612,608 |
An enterprise-grade, type-safe dependency injection framework for Rust with advanced features including async support, AOP patterns, module systems, and comprehensive reliability mechanisms.
Send + Sync
with lock-free hot pathsAdd ferrous-di to your Cargo.toml
:
[dependencies]
ferrous-di = "0.1"
# With performance optimizations
ferrous-di = { version = "0.1", features = ["performance"] }
# With async support
ferrous-di = { version = "0.1", features = ["async"] }
# With diagnostics and debugging
ferrous-di = { version = "0.1", features = ["diagnostics"] }
# All features enabled
ferrous-di = { version = "0.1", features = ["performance", "async", "diagnostics"] }
use ferrous_di::{ServiceCollection, Lifetime};
use std::sync::Arc;
// Define your services
struct Database {
connection_string: String,
}
struct UserService {
db: Arc<Database>,
}
trait Logger: Send + Sync {
fn log(&self, message: &str);
}
struct ConsoleLogger;
impl Logger for ConsoleLogger {
fn log(&self, message: &str) {
println!("[LOG] {}", message);
}
}
// Configure services
let mut services = ServiceCollection::new();
// Register singleton
services.add_singleton(Database {
connection_string: "postgresql://localhost".to_string(),
});
// Register with factory
services.add_scoped_factory::<UserService, _>(|resolver| {
UserService {
db: resolver.get_required::<Database>(),
}
});
// Register trait
services.add_singleton_trait::<dyn Logger, _>(ConsoleLogger);
// Build provider
let provider = services.build();
// Resolve services
let db = provider.get_required::<Database>();
let logger = provider.get_required_trait::<dyn Logger>();
// Create scope for scoped services
let scope = provider.create_scope();
let user_service = scope.get_required::<UserService>();
Single instance per root provider, cached forever:
services.add_singleton(ExpensiveResource::new());
services.add_singleton_factory::<Database, _>(|_| {
Database::connect("postgresql://localhost")
});
Single instance per scope, cached for scope lifetime:
services.add_scoped_factory::<RequestContext, _>(|_| {
RequestContext::new(generate_request_id())
});
let scope = provider.create_scope();
let ctx1 = scope.get_required::<RequestContext>(); // Creates new
let ctx2 = scope.get_required::<RequestContext>(); // Returns same instance
New instance per resolution, never cached:
services.add_transient_factory::<Command, _>(|resolver| {
Command::new(resolver.get_required::<Database>())
});
trait EmailService: Send + Sync {
fn send(&self, to: &str, subject: &str, body: &str);
}
struct SmtpEmailService;
impl EmailService for SmtpEmailService {
fn send(&self, to: &str, subject: &str, body: &str) {
// SMTP implementation
}
}
// Register trait implementation
services.add_singleton_trait::<dyn EmailService, _>(SmtpEmailService);
// Resolve single implementation
let email_service = provider.get_required_trait::<dyn EmailService>();
trait Plugin: Send + Sync {
fn name(&self) -> &str;
fn execute(&self);
}
// Register multiple implementations
services.add_trait_implementation::<dyn Plugin, _>(AuthPlugin, Lifetime::Singleton);
services.add_trait_implementation::<dyn Plugin, _>(LoggingPlugin, Lifetime::Singleton);
services.add_trait_implementation::<dyn Plugin, _>(MetricsPlugin, Lifetime::Transient);
// Resolve all implementations
let plugins = provider.get_all_trait::<dyn Plugin>().unwrap();
for plugin in plugins {
plugin.execute();
}
Ferrous DI provides detailed error information:
use ferrous_di::DiError;
match provider.get::<UnregisteredService>() {
Ok(service) => { /* use service */ }
Err(DiError::NotFound(name)) => {
eprintln!("Service not found: {}", name);
}
Err(DiError::Circular(path)) => {
eprintln!("Circular dependency: {}", path.join(" -> "));
}
Err(DiError::WrongLifetime(msg)) => {
eprintln!("Lifetime error: {}", msg);
}
Err(e) => {
eprintln!("DI error: {}", e);
}
}
For convenience, use the get_required_*
methods that panic on error:
let service = provider.get_required::<MyService>(); // Panics if not found
let trait_service = provider.get_required_trait::<dyn MyTrait>();
See examples/web_server_scope.rs for a complete example showing:
cargo run --example web_server_scope
See examples/modular_registration.rs for advanced patterns:
cargo run --example modular_registration
See examples/durable-agent/ for a complete agent system:
cd examples/durable-agent
cargo run
use ferrous_di::async_factories::AsyncFactory;
// Async service factory
struct DatabaseConnection;
#[async_trait]
impl AsyncFactory<DatabaseConnection> for DatabaseConnectionFactory {
async fn create(&self, resolver: &dyn Resolver) -> DiResult<DatabaseConnection> {
let config = resolver.get_required::<DatabaseConfig>();
DatabaseConnection::connect(&config.url).await
}
}
services.add_async_singleton_factory(DatabaseConnectionFactory);
use ferrous_di::decoration::ServiceDecorator;
// Logging decorator
struct LoggingDecorator<T> {
inner: Arc<T>,
logger: Arc<dyn Logger>,
}
impl<T: UserService> UserService for LoggingDecorator<T> {
fn get_user(&self, id: UserId) -> Result<User, UserError> {
self.logger.info(&format!("Getting user {}", id));
let result = self.inner.get_user(id);
match &result {
Ok(_) => self.logger.info("User retrieved successfully"),
Err(e) => self.logger.error(&format!("Failed to get user: {}", e)),
}
result
}
}
services.add_decorator::<dyn UserService, _>(LoggingDecoratorFactory);
struct Config { /* ... */ }
struct Database { config: Arc<Config> }
struct UserRepository { db: Arc<Database> }
struct UserService { repo: Arc<UserRepository> }
services.add_singleton(Config::load());
services.add_singleton_factory::<Database, _>(|r| {
Database::new(r.get_required::<Config>())
});
services.add_scoped_factory::<UserRepository, _>(|r| {
UserRepository::new(r.get_required::<Database>())
});
services.add_transient_factory::<UserService, _>(|r| {
UserService::new(r.get_required::<UserRepository>())
});
use ferrous_di::collection::Module;
// Database module
struct DatabaseModule;
impl Module for DatabaseModule {
fn configure(&self, services: &mut ServiceCollection) -> DiResult<()> {
services.add_singleton_factory::<DatabasePool, _>(|r| {
DatabasePool::new(r.get_required::<DatabaseConfig>())
});
services.add_scoped_factory::<UnitOfWork, _>(|r| {
UnitOfWork::new(r.get_required::<DatabasePool>())
});
Ok(())
}
}
// Application composition
let mut services = ServiceCollection::new();
services.add_module(DatabaseModule)?;
services.add_module(BusinessLogicModule)?;
services.add_module(WebModule)?;
Ferrous DI is designed for high-performance dependency injection with enterprise-grade capabilities.
Measured on Apple Silicon, compiled with --release
:
Operation | Time | Notes |
---|---|---|
Singleton hit | ~78ns | Cached singleton resolution (hot path) |
Singleton cold | ~437ns | First-time singleton creation with factory |
Scoped hit | ~83ns | Cached scoped service within same scope |
Transient | ~68ns | Fresh instance creation each time |
Concrete vs Trait | ~86ns vs ~82ns | Minimal difference between concrete and trait |
Multi-binding (16 services) | ~850ns | Resolving all 16 implementations |
Scope create/drop | ~18ns | Empty scope lifecycle overhead |
Circular detection (depth 8) | ~87ns | Deep dependency chain validation |
Using pattern (empty) | ~152ns | Minimal overhead for scoped disposal |
Mixed workload | ~872ns | Realistic 70/20/10 singleton/scoped/transient mix |
Threads | Time per Op | Throughput | Scaling |
---|---|---|---|
1 thread | ~79ns | ~12.6M ops/sec | Baseline |
2 threads | ~155ns | ~12.9M ops/sec total | Good parallelization |
4 threads | ~206ns | ~19.4M ops/sec total | Continued scaling |
8 threads | ~168ns | ~47.6M ops/sec total | Excellent multi-core utilization |
Enable high-performance optimizations with Cargo features:
[dependencies]
ferrous-di = { version = "0.1", features = ["performance"] }
This enables all performance features:
parking-lot
: Faster mutex implementation (2-3x faster locking)ahash
: High-performance hashing algorithmsmallvec
: Stack-allocated vectors for small circular detection stacksonce-cell
: Lock-free singleton caching (planned)Enable features selectively if you prefer:
[dependencies]
ferrous-di = { version = "0.1", features = ["parking-lot", "ahash"] }
To reproduce benchmarks on your hardware:
# Clone the repository
git clone https://github.com/s1ntropy/ferrous-di
cd ferrous-di
# Run benchmarks with performance features
cargo bench --features performance
# Run specific benchmarks
cargo bench --features performance -- singleton_hit
cargo bench --features performance -- contention
cargo bench --features performance -- mixed_workload
# Generate HTML reports (if gnuplot available)
cargo bench --features performance -- --output-format html
The library implements several performance optimizations:
The library is optimized with aggressive release settings:
[profile.release]
opt-level = 3
lto = "fat"
codegen-units = 1
debug = false
This provides maximum performance for production use.
std
(default)Standard library support with std collections and threading:
[dependencies]
ferrous-di = "0.1" # includes std by default
async
Enable async factories and lifecycle management:
[dependencies]
ferrous-di = { version = "0.1", features = ["async"] }
use ferrous_di::async_factories::AsyncFactory;
// Async service creation
services.add_async_singleton_factory(DatabaseConnectionFactory);
let connection = provider.get_async::<DatabaseConnection>().await?;
performance
Enable all performance optimizations:
[dependencies]
ferrous-di = { version = "0.1", features = ["performance"] }
Individual performance features:
parking-lot
: Faster mutex implementation (2-3x faster locking)ahash
: High-performance hashing algorithmsmallvec
: Stack-allocated vectors for small collectionsonce-cell
: Lock-free singleton caching (experimental)diagnostics
Enable comprehensive debugging and diagnostic tools:
[dependencies]
ferrous-di = { version = "0.1", features = ["diagnostics"] }
#[cfg(feature = "diagnostics")]
{
// Service graph visualization
let graph = provider.export_service_graph()?;
println!("{}", graph.to_dot_format());
// Debugging information
println!("{}", provider.to_debug_string());
// Performance metrics
let metrics = provider.get_metrics();
println!("Resolution time: {:?}", metrics.avg_resolution_time);
}
validation
Enable service validation and health checks:
[dependencies]
ferrous-di = { version = "0.1", features = ["validation"] }
web
Web framework integration patterns:
[dependencies]
ferrous-di = { version = "0.1", features = ["web"] }
metrics
Built-in metrics and telemetry:
[dependencies]
ferrous-di = { version = "0.1", features = ["metrics"] }
experimental
Cutting-edge features under development:
[dependencies]
ferrous-di = { version = "0.1", features = ["experimental"] }
โ ๏ธ Note: Experimental features may change or be removed in minor versions.
Run the complete test suite:
cargo test
Run specific test categories:
cargo test basics # Basic functionality tests
cargo test scopes # Scoped service tests
cargo test circular # Circular dependency tests
cargo test advanced_features # Named services, metadata, TryAdd
cargo test agent_features # Durable agent patterns
cargo test modules # Module system tests
cargo test disposal # Resource cleanup tests
Test the quality of your tests with mutation testing:
cargo install cargo-mutants
cargo mutants
Run property-based and fuzz testing:
cargo install cargo-fuzz
cargo fuzz run dependency_injection
cargo fuzz run service_registration
cargo fuzz run service_resolution
Scan for security vulnerabilities:
cargo audit
Run performance benchmarks:
cargo bench --features performance
Generate code coverage reports:
cargo install cargo-tarpaulin
cargo tarpaulin --out html --features performance
See ROADMAP.md for detailed feature plans and timelines.
We welcome contributions from the community! This project follows professional development practices:
For security vulnerabilities, please see SECURITY.md for responsible disclosure.
Licensed under either of:
at your option.
Ferrous DI is actively developed and maintained with professional development practices:
Ready for Production: Suitable for enterprise applications requiring high performance, reliability, and maintainability.
For questions, issues, or contributions, visit our GitHub repository.
Feature | Ferrous DI | MS.DI | Notes |
---|---|---|---|
Type Safety | Compile-time | Runtime | Zero-cost abstractions vs reflection |
Performance | ~78ns resolution | ~1000ns+ | TypeId-based O(1) lookups |
Memory Safety | Built-in Arc sharing | Manual lifecycle | Rust ownership + Arc |
Async Support | Native async/await | Task-based | First-class async factories |
Lifetimes | Singleton, Scoped, Transient | Same | Compatible lifecycle semantics |
Multi-binding | Explicit append semantics | Implicit append | Clear intention |
Circular Detection | Compile + Runtime | Runtime | Multi-layered protection |
Thread Safety | Lock-free hot paths | Thread-safe | Optimized for concurrent access |
Modularity | Hierarchical modules | Service collections | Advanced composition |
Diagnostics | Built-in graph export | Limited | Rich debugging capabilities |
AOP Support | Native decoration | Third-party | Built-in interception |
Reliability | Circuit breakers, retries | Manual | Enterprise patterns |