SaDi - Semi-automatic Dependency Injector
A lightweight, type-safe dependency injection container for Rust applications. SaDi provides ergonomic service registration (including trait-object bindings), transient and singleton lifetimes, semi-automatic dependency resolution, and circular dependency detection.
โจ Features
- ๐ Type-Safe: Leverages Rust's type system for compile-time safety
- ๐ Transient Services: Create new instances on each request
- ๐ Singleton Services: Shared instances with reference counting
- ๐ Circular Detection: Prevents infinite loops in dependency graphs
- โ Error Handling: Comprehensive error types with detailed messages
- ๐ Optional Logging: Tracing integration with feature gates
- ๐ Zero-Cost Abstractions: Feature gates enable compile-time optimization
๐ฆ Installation
Add this to your Cargo.toml:
[]
= "0.2.1"
๐ Quick Start
use ;
use Rc;
// Define your services (non-thread-safe default uses `Rc` via `Shared`)
๐ Usage Guide
Service Registration
Transient Services
Create new instances on each request. The default bind registration is transient:
use ;
use Uuid;
let c = container! ;
let logger1 = c..unwrap;
let logger2 = c..unwrap;
Singleton Services
Create once and share across all dependents. Use the singleton annotation in bind:
use ;
let c = container! ;
let config1 = c..unwrap;
let config2 = c..unwrap;
assert!;
Error Handling
SaDi provides both panicking and non-panicking variants:
use ;
let c = new;
c..unwrap;
// Resolve (panicking)
let service = c..unwrap;
// Non-panicking
match c.
// Trying to resolve an unregistered type
match c.
Dependency Injection
Services can depend on other services. Use the container! macro to register bindings concisely:
use ;
let c = container! ;
let repo = c..unwrap;
๐ Advanced Features
Circular Dependency Detection
SaDi automatically detects and prevents circular dependencies:
use Container;
// Example: registering circular dependencies will produce a descriptive error at runtime
let c = new;
// c.bind_concrete::<ServiceA, ServiceA, _>(|c| { let _ = c.resolve::<ServiceB>(); ServiceA });
// c.bind_concrete::<ServiceB, ServiceB, _>(|c| { let _ = c.resolve::<ServiceA>(); ServiceB });
match c.
Tracing Integration
Enable the tracing feature for automatic logging (the crate's default feature includes tracing):
[]
= { = "0.2.1", = ["tracing"] }
use ;
use info;
async
๐งช Testing
Run the test suite:
# Run all tests for the workspace
# Run tests for the sadi crate only
# Run with tracing feature
# Run documentation tests
# Run example
๐ Project Structure
sadi/
โโโ sadi/ # library crate
โ โโโ src/ # core implementation (container, macros, types)
โโโ examples/
โ โโโ basic/ # Comprehensive usage example
โโโ README.md # This file
๐ง Configuration
Feature Flags
SaDi exposes a small set of feature flags. See sadi/Cargo.toml for the authoritative list, but the crate currently defines:
thread-safe(enabled by default) โ switches internal shared pointer and synchronization primitives toArc+RwLock/Mutexfor thread-safe containers.tracing(enabled by default) โ integrates with thetracingcrate to emit logs during registration/resolution.
The workspace default enables both thread-safe and tracing. To opt out of thread-safe behavior (use Rc instead of Arc), disable the thread-safe feature.
Environment Variables
When using the tracing feature, you can control logging levels:
# Set log level
RUST_LOG=debug
# Enable only SaDi logs
RUST_LOG=sadi=info
๐ค Contributing
Contributions are welcome! Please feel free to submit a Pull Request. For major changes, please open an issue first to discuss what you would like to change.
Development Setup
- Clone the repository:
- Run tests:
- Check formatting:
- Run clippy:
๐ Roadmap & TODO
๐ Async Support
- Async Factory Functions: Support for
async fnfactories - Async Service Resolution: Non-blocking service creation
- Async Singleton Caching: Thread-safe async singleton management
- Async Circular Detection: Proper handling in async contexts
๐งต Thread Safety
- Arc-based Container: Thread-safe version of SaDi using
Arcinstead ofRc(implemented behind thethread-safefeature) - Send + Sync Services: Support for
Send + Syncservices in thread-safe mode (enforced by API bounds) - Concurrent Access: Concurrent reads/writes supported via
RwLock/Mutexin thread-safe mode - Lock-free Operations: Minimize contention in high-concurrency scenarios
๐ง Advanced Features
- Service Scoping: Request-scoped, thread-scoped service lifetimes
- Lazy Initialization: Singleton instances are created on first
provide(implemented inFactory) - Service Decorators: Middleware/decoration patterns for services
- Conditional Registration: Register services based on runtime conditions
- Service Health Checks: Built-in health monitoring for services
- Service Metrics: Performance and usage statistics
๐ฆ Ecosystem Integration
- Tokio Integration: First-class support for Tokio runtime
- Actix-web Plugin: Direct integration with Actix-web framework
- Axum Integration: Support for Axum web framework
- Tower Service: Implement Tower service trait
- Serde Support: Serialize/deserialize container configuration
๐ ๏ธ Developer Experience
- Derive Macros: Auto-generate factory functions from service structs
- Builder Validation: Compile-time validation of dependency graphs
- Error Suggestions: Better error messages with fix suggestions
- IDE Integration: Language server support for dependency analysis
- Container Visualization: Graphical representation of service dependencies
๐ Security & Reliability
- Service Isolation: Sandboxing for untrusted services
- Resource Limits: Memory and CPU limits per service
- Graceful Shutdown: Proper cleanup on container disposal
- Fault Tolerance: Circuit breaker pattern for failing services
๐ Observability
- OpenTelemetry: Built-in telemetry and distributed tracing
- Prometheus Metrics: Expose container metrics for monitoring
- Service Discovery: Integration with service discovery systems
- Health Endpoints: HTTP endpoints for container health checks
๐ฏ Performance
- Compile-time validation / Builder checks: Improve compile-time validation and builder-time checks for dependency graphs
- Service Pooling: Object pooling for expensive-to-create services
- Memory Optimization: Reduced memory footprint for large containers
๐ Long-term Wishlist
- Hot Reloading: Dynamic service replacement without container restart (large, architecture-level feature; moved to long-term wishlist)
๐ License
This project is licensed under the MIT License - see the LICENSE file for details.
๐ Acknowledgments
- Inspired by dependency injection patterns from other languages and frameworks
- Built with โค๏ธ using Rust's powerful type system
- Thanks to the Rust community for excellent crates and documentation
Made with โค๏ธ by Joรฃo Pedro Martins