Experimental IOC library inspired by injector for Rust. Goals: IOC + ergonomics.
See test suite for all supported usages.
Examples
using #[inject]
, call!
, get!
and container!
.
-
Configure a container, add some provider, e.g an
Arc
use std::sync::Arc; use ::inject::{container, get, inject}; struct Instance(pub isize); impl Instance { #[inject] fn new(a: isize) -> Self { Instance(a) } } fn main() { let provider = Arc::new(Instance(3)); // Install the Arc as a reference provider, anytime using get! // will resolve to a reference of this Arc. let container = container![ref provider]; let instance: &Instance = get!(&container, &Instance).unwrap(); assert_eq!(3, instance.0) }
-
Let the container resolve a dependency, using a closure as provider
use ::inject::{Container, container, get, inject}; struct Instance(pub isize); impl Instance { #[inject] fn new(a: isize) -> Self { Instance(a) } } struct Service { a: Instance, } impl Service { #[inject] fn new(instance: Instance) -> Self { Self { a: instance } } } fn main() { // Install a provider, this time a closure returning a value let container = container![|container: &Container| Ok(Instance(2))]; let service: Service = get!(&container, Service).unwrap(); assert_eq!(service.a.0, 2) }
-
Sometimes, calling a function with injection is useful,
use ::inject::{call, Container, container, inject}; struct Service(isize); impl Service { #[inject] fn new() -> Self { Self(0) } } #[inject] fn acts_on_service(service: Service) -> isize { 2 + service.0 } fn main() { let container = container![|container: &Container| Ok(Service(3))]; let result = call!(&container, acts_on_service).unwrap(); assert_eq!(result, 5) }
-
call!
supports a kwarg-flavored syntaxuse ::inject::{call, container, inject}; struct Service(isize); impl Service { #[inject] fn new() -> Self { Self(0) } } #[inject] fn acts_on_service(service: Service) -> isize { 2 + service.0 } fn main() { let container = container![]; let result = call!(&container, acts_on_service, kwargs = { service: Service(2) }).unwrap(); assert_eq!(result, 4) }
-
Dependency resolution can rely upon a type implementing the
Default
traituse inject::{container, get}; #[derive(Default)] struct Service(isize); fn main() { let container = container![]; let service = get!(&container, Service).unwrap(); assert_eq!(service.0, 0) }
Details
The get!
macro with a container
resolves a type in order of: installed provider (1), calling the associated inject
function (often generated with #[inject]
) function on a type (2), and lastly the Default
trait (3).
(2) & (3) can be opt-out by attribute #[inject(no_inject(arg))]
, (name tbd) in which case only container held provider will be used for resolution of the type. Method specific defaults are annotated as #[inject(defualt(arg = expression))]
where expression will lazy evaluate on failing attempt at (1) and (2).
Todo:
- Support kwargs for "constructors" with a
create_object!
flavored macro. - Make
#[inject]
support Struct attribute notation with#[inject(..)]
for individual struct fields. - Make
default
andno_inject
story less annoying.