A simple and lightweight dependency injection container for Rust.
- Simple and lightweight
- Thread-safe
- Support for both transient and singleton services
- Both sync (
Di) and async (TkDi) containers - No runtime overhead
- Zero dependencies for sync container
Add this to your Cargo.toml:
[dependencies]
ru-di = "0.2"The Di container provides dependency injection for synchronous code.
use ru_di::Di;
// Define your services
struct Database {
port: u16,
}
struct AppService {
db: Database,
}
// Register services
Di::register::<Database, _>(|_| Database { port: 3306 });
Di::register::<AppService, _>(|di| {
let db = di.get_inner::<Database>().unwrap();
AppService { db: db.clone() }
});
// Get service instance
let app = Di::get::<AppService>().unwrap();
assert_eq!(app.db.port, 3306);use ru_di::Di;
#[derive(Debug, PartialEq)]
struct Configuration {
port: u16,
}
// Register a singleton
Di::register_single(Configuration { port: 8080 });
// Get singleton instance
if let Some(mut config) = Di::get_single::<Configuration>() {
let mut config = config.get_mut().unwrap();
assert_eq!(config.port, 8080);
config.port = 8081;
}
// The change persists
if let Some(mut config) = Di::get_single::<Configuration>() {
let config = config.get_mut().unwrap();
assert_eq!(config.port, 8081);
}The TkDi container provides dependency injection for async/await code with Tokio.
use ru_di::TkDi;
#[derive(Clone)]
struct Database {
port: u16,
}
struct AppService {
db: Database,
}
// Register services (factory receives &TkDi parameter)
TkDi::register(|_di| Database { port: 3306 }).await;
// Register services with dependencies
TkDi::register(|_di| {
AppService { db: Database { port: 3307 } }
}).await;
// Get service instance
let app = TkDi::get::<AppService>().await.unwrap();
assert_eq!(app.db.port, 3307);
// Register and use singletons
TkDi::register_single(Configuration { port: 8080 }).await;
if let Some(mut config) = TkDi::get_single::<Configuration>().await {
let mut config = config.get_mut().await;
assert_eq!(config.port, 8080);
config.port = 8081;
}Di::register<T, F>(factory: F)- Register a transient serviceT: Service type (must be'static + Send + Sync)F: Factory closureFn(&Di) -> T
Di::register_single<T>(instance: T)- Register a singleton service
Di::get<T>() -> Result<T, DiError>- Get a transient service instanceDi::get_single<T>() -> Option<SingleRef<T>>- Get a singleton service instanceSingleRef<T>::get(&self) -> Result<RwLockReadGuard<'_, T>, DiError>- Get read accessSingleRef<T>::get_mut(&mut self) -> Result<RwLockWriteGuard<'_, T>, DiError>- Get write access
TkDi::register<T, F>(factory: F)- Register a transient serviceT: Service type (must be'static + Send + Sync)F: Factory closureFn(&TkDi) -> T
TkDi::register_single<T>(instance: T)- Register a singleton service
TkDi::get<T>() -> Result<T, DiError>- Get a transient service instanceTkDi::get_single<T>() -> Option<SingleAsyncRef<T>>- Get a singleton service instanceSingleAsyncRef<T>::get(&self)- Get read access (returnsRwLockReadGuard)SingleAsyncRef<T>::get_mut(&mut self)- Get write access (returnsRwLockWriteGuard)
DiError::ProviderNotFound- Service provider not registeredDiError::TypeMismatch- Type conversion failedDiError::LockError- Lock acquisition failed
All operations are thread-safe:
DiusesArc,Mutex, andRwLockfrom stdTkDiusesArc,TokioMutex, andTokioRwLockfor async compatibility
This project is licensed under the MIT License - see the LICENSE file for details.