Crates.io | dill-impl |
lib.rs | dill-impl |
version | 0.10.0 |
source | src |
created_at | 2021-07-09 17:44:43.445476 |
updated_at | 2024-12-10 01:39:34.866749 |
description | Implementation details of the dill DI library. |
homepage | https://github.com/sergiimk/dill-rs |
repository | https://github.com/sergiimk/dill-rs |
max_upload_size | |
id | 420837 |
size | 29,041 |
This crate is still in early stages and needs a lot of work, BUT it's in active use in kamu-cli
- a fairly large project organized according to Onion/Clean Architecture. We are continuing to improve this crate as we go and encounter more sophisticated DI scenarios.
/////////////////////////////////////////
// Define interfaces in traits
trait A: Send + Sync {
fn test(&self) -> String;
}
// Implement traits to define components
#[component]
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;
}
#[component]
struct BImpl;
impl B for BImpl {
fn test(&self) -> String {
"bimpl".to_owned()
}
}
/////////////////////////////////////////
// Register interfaces and bind them to implementations
let cat = Catalog::builder()
.add::<AImpl>()
.bind::<dyn A, AImpl>()
.add::<BImpl>()
.bind::<dyn B, BImpl>()
.build();
// Get objects and have their deps satisfied automatically
let inst = cat.get::<OneOf<dyn A>>().unwrap();
assert_eq!(inst.test(), "aimpl::bimpl");
Injection specs:
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 requestedComponent scopes:
Transient
(default) - a new instance is created for every invocationSingleton
- an instance is created upon first use and then reused for the rest of calls#[component]
macro can derive Builder
:
struct
or on impl
block with Impl::new()
functionArc<T>
, T: Clone
, &T
Option<T>
is interpreted as Maybe<OneOf<T>>
specVec<T>
is interpreted as AllOf<T>
specBuilder
#[interface]
attribute#[meta(...)]
attributePrebuilt / add by value support
By value injection of Clone
types
Catalog
can be self-injected
Chaining of Catalog
s allows adding values dynamically (e.g. in middleware chains like tower
)
Catalog
can be scoped within a tokio
task as "current" to override the source of Lazy
ly injected values
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
rustScope
s external to Builder
s 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
)