# auto-di
Automatic dependency injection for Rust, backed by a global `inventory`
registry and async-safe initialization. The core API intentionally stays
small: use `#[singleton]` for constructor injection and `#[provider]` for factory
injection.
## Components and constructor injection
```rust
use std::sync::Arc;
use auto_di::singleton;
trait Users: Send + Sync {}
#[singleton(name = "postgres", primary)]
fn users() -> Arc<dyn Users> {
Arc::new(PostgresUsers)
}
#[singleton(eager, post_construct = "start", pre_destroy = "stop")]
impl UserService {
fn new(#[qualifier("postgres")] users: Arc<dyn Users>) -> Self {
Self { users }
}
async fn start(&self) {}
async fn stop(&self) {}
}
```
`#[singleton]` supports these options:
- `name = "..."`
- `primary`
- `scope = "singleton" | "prototype" | "request"`
- `eager`
- `profile = "development"`
- `condition = "ENV_KEY"` or `condition = "ENV_KEY=value"`
- `post_construct = "async_method"`
- `pre_destroy = "async_method"`
Constructors accept `Arc<T>`, `Option<Arc<T>>`, `Vec<Arc<T>>`, `Provider<T>`,
and `Lazy<T>`. Both sync and async constructors are supported.
## Providers
Providers can be declared in any module:
```rust
#[provider]
fn database_pool() -> DatabasePool {
DatabasePool::new()
}
```
Singletons automatically discover nested providers:
```rust
#[singleton]
impl UserService {
fn new(repository: Arc<UserRepository>) -> Self {
Self { repository }
}
#[provider]
fn user_cache(&self) -> UserCache {
UserCache::new()
}
}
```
```rust
#[derive(Default)]
struct Beans;
#[configuration]
impl Beans {
#[provider]
fn config(&self) -> Config { Config::default() }
#[provider(name = "main", primary)]
async fn database(&self, config: Arc<Config>) -> Database {
Database::connect(&config).await
}
}
```
## Environment properties
```rust
#[configuration_properties("database")]
struct DatabaseProperties {
url: String, // DATABASE_URL
pool_size: usize, // DATABASE_POOL_SIZE
}
```
## Application and request scopes
```rust
#[application]
async fn main() -> Result<(), Box<dyn std::error::Error>> {
let service = auto_di::resolve::<UserService>().await?;
Ok(())
}
let request = auto_di::global_container()?.request_context();
let dependency = request.resolve::<RequestDependency>().await?;
```
Active profiles come from comma-separated `APP_PROFILES`, or can be selected
explicitly with `Container::with_profiles(...)`.