Expand description
Runtime dependency injection.
Documentation is under construction!
§Examples
§Basic dependency resolution
As a user of type A we only care about getting an instance to use - the
life-cycle of A and its dependencies remain hidden from us.
use dill::*;
use std::sync::Arc;
#[component]
struct A {
b: Arc<B>, // An instance of `B` will be resolved and injected when requesting `A`
}
impl A {
fn foo(&self) -> String {
format!("a::{}", self.b.bar())
}
}
#[component]
struct B;
impl B {
fn bar(&self) -> String {
"b".to_string()
}
}
let catalog = Catalog::builder()
.add::<A>()
.add::<B>()
.build();
let a = catalog.get_one::<A>().unwrap();
assert_eq!(a.foo(), "a::b");§Using trait objects (aka Interfaces)
Every type can be associated with multiple traits that it implements using
CatalogBuilder::bind() method, allowing dynamically picking the best
implementation to use (e.g. based on config) or even using multiple
implementations at once (e.g. plugins).
use dill::*;
use std::sync::Arc;
// An interface that has two implementations below
trait A: Send + Sync {
fn foo(&self) -> String;
}
#[component]
struct AImpl1;
impl A for AImpl1 {
fn foo(&self) -> String {
"aimpl1".to_string()
}
}
#[component]
struct AImpl2;
impl A for AImpl2 {
fn foo(&self) -> String {
"aimpl2".to_string()
}
}
let catalog = Catalog::builder()
.add::<AImpl1>()
.bind::<dyn A, AImpl1>()
.add::<AImpl2>()
.bind::<dyn A, AImpl2>()
.build();
// AllOf<T> is a DependencySpec that returns instances of all types that implement trait T
let ays = catalog.get::<AllOf<dyn A>>().unwrap();
let mut foos: Vec<_> = ays.iter().map(|a| a.foo()).collect();
foos.sort(); // Order is undefined
assert_eq!(foos, vec!["aimpl1".to_owned(), "aimpl2".to_owned()]);§Controlling lifetimes with Scopes
The life-cycle of a type is no longer controlled by the user of a type.
Author of type A below can choose whether A should be created per call
(Transient) or reused by all clients (Singleton).
use dill::*;
#[component]
#[scope(Singleton)]
struct A {
// Needed for compiler not to optimize type out
name: String,
}
impl A {
fn test(&self) -> String {
format!("a::{}", self.name)
}
}
let cat = Catalog::builder()
.add::<A>()
.add_value("foo".to_owned())
.build();
let inst1 = cat.get::<OneOf<A>>().unwrap();
let inst2 = cat.get::<OneOf<A>>().unwrap();
// Expecting Singleton scope to return same instance
assert_eq!(
inst1.as_ref() as *const A,
inst2.as_ref() as *const A
);§Parametrizing builders
Builders can be parametrized during the registration process for convenience (e.g. with values read from configuration).
use dill::*;
#[component]
#[scope(Singleton)]
struct ConnectionPool {
host: String,
port: i32,
}
impl ConnectionPool {
fn url(&self) -> String {
format!("http://{}:{}", self.host, self.port)
}
}
let cat = Catalog::builder()
.add_builder(
ConnectionPool::builder()
.with_host("foo".to_owned())
.with_port(8080),
)
.build();
let inst = cat.get::<OneOf<ConnectionPool>>().unwrap();
assert_eq!(inst.url(), "http://foo:8080");Re-exports§
Modules§
Structs§
- Ambiguous
Type Error - Catalog
- Catalog
Builder - Catalog
Weak Ref - A weak reference to the
Catalogthat can be safely injected into the components and used as a factory. While generally considered an anti-pattern, this provides a great flexibility over when and how instances are constructed. - Dependency
Info - Injection
Context - Injection
Stack - Lazy
- Represents a value whose construction is delayed upon request rather than resolved from the catalog immediately. This is often useful in cases when some expensive type is used rarely, thus it’s beneficial to only construct it on-demand.
- Scope
Inversion Error - Type
Info - Typecast
Builder - Takes a dynamic
Builderand casts the instance to desired interface - Typed
Builder Without Default Interfaces - A wrapper builder that stops it from auto-registering default interfaces
- Unregistered
Type Error - Validation
Error
Enums§
Traits§
- Builder
- Builders are responsible for resolving dependencies and creating new instances of a certain type. Builders typically create new instances for every call, delegating the lifetime management to Scopes,
- Builder
Ext - Component
- Allows CatalogBuilder::add() to accept types with associated builder
- Typed
Builder - Typed
Builder Cast - Typed
Builder Ext - Validation
Error Ext