Experimental IOC library inpsired 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
```rust
use std::sync::Arc;
use ::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
```rust use ::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, ```rust use ::inject::*;
struct Service(isize);
impl Service { #[inject] fn new() -> Self { Self(0) } }
fn actsonservice(service: Service) -> isize { 2 + service.0 }
fn main() { let container = container![ |container: &Container| Ok(Service(3)) ];
let result = call!(&container, actsonservice).unwrap();
assert_eq!(result, 5) } ```
call!
supports a kwarg-flavored syntax
```rust
use ::inject::*;
struct Service(isize);
impl Service { #[inject] fn new() -> Self { Self(0) } }
fn actsonservice(service: Service) -> isize { 2 + service.0 }
fn main() { let container = container![];
let result = call!(&container, actsonservice, kwargs = { service: Service(2) }).unwrap();
assert_eq!(result, 4) } ```
Dependency resolution can rely upon a type implementing the Default
trait
```rust
use ::inject::*;
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:
1. Support kwargs for "constructors" with a create_object!
flavored macro.
2. Make #[inject]
support Struct attribute notation with #[inject(..)]
for individual struct fields.
3. Make default
and no_inject
story less annoying.