| Crates.io | dill |
| lib.rs | dill |
| version | 0.15.0 |
| created_at | 2021-07-09 17:45:45.784074+00 |
| updated_at | 2026-01-03 19:56:25.970397+00 |
| description | Runtime depenency injection library. |
| homepage | https://github.com/sergiimk/dill-rs |
| repository | https://github.com/sergiimk/dill-rs |
| max_upload_size | |
| id | 420841 |
| size | 87,881 |
/////////////////////////////////////////
// Define interfaces in traits
trait A: Send + Sync {
fn test(&self) -> String;
}
// Implement traits to define components
#[dill::component]
#[dill::interface(dyn A)]
struct AImpl {
// Auto-inject dependencies (also supports by-value)
b: Arc<dyn B>,
}
impl A for AImpl {
fn test(&self) -> String {
format!("aimpl::{}", self.b.test())
}
}
/////////////////////////////////////////
trait B: Send + Sync {
fn test(&self) -> String;
}
#[dill::component]
#[dill::interface(dyn B)]
struct BImpl;
impl B for BImpl {
fn test(&self) -> String {
"bimpl".to_owned()
}
}
/////////////////////////////////////////
// Register components
let cat = Catalog::builder()
.add::<AImpl>()
.add::<BImpl>()
.build();
// Get objects and have their deps satisfied automatically
let inst = cat.get::<OneOf<dyn A>>().unwrap();
assert_eq!(inst.test(), "aimpl::bimpl");
While documentation is still lacking, this crate is production-ready and is in active use in kamu-cli - a fairly large project organized according to Onion/Clean Architecture.
OneOf - expects a single implementation of a given interfaceAllOf - returns a collection of all implementations on a given interfaceMaybe<Spec> - returns None if inner Spec cannot be resolvedLazy<Spec> - injects an object that delays the creation of value until it is requestedTransient (default) - short-lived, a new instance is created for every invocationAgnostic - same as Transient but signals that it's OK to inject this instance into more long-lived scopesSingleton - an instance is created upon first use and then reused for the rest of callsTransaction - an instance will be cached for the duration of a transaction#[component] macro can derive Builder:
struct or on impl block with Impl::new() functionArc<T>, T: Clone, &TOption<T> is interpreted as Maybe<OneOf<T>> specVec<T> is interpreted as AllOf<T> specBuilder#[interface] attribute#[meta(...)] attributeClone typesCatalog can be self-injectedCatalogs allows adding values dynamically (e.g. in middleware chains like tower)CatalogBuilder::validate() performs static analysis to detect dangling and ambiguous dependencies and scope inversion issuesCatalog can be scoped within a tokio task as "current" to override the source of Lazyly injected valuesdill::utils::graphviz and dill::utils::plantuml allow visualizing the dependency graph
The type implementor (and not type user) usually has the best knowledge of what the optimal lifecycle for the type should be and its concurrency characteristics, thus implementors should be in control of the defaults
stable rustScopes external to Builders so they could be overriddenArc, Option, Vec to dependency specs instead of relying on macro magictrybuild tests (see https://youtu.be/geovSK3wMB8?t=956)add_* with generic add<B: Into<Builder>>new()Arc<dyn Iface> can be hidden behind a movable object
This even further hides lifetime management from consumers
Allows generic methods to be implemented to improve usability of dyn Trait (e.g. accepting impl AsRef<str> parameters instead of &str)