Experimental IOC library inpsired by injector for Rust. Goals: IOC + ergonomics.
See test suite for all supported usages.
Example quick-fire usages:
```rust use std::sync::Arc;
use ::inject::*;
struct Instance(pub isize);
impl Instance { #[inject] pub fn new(a: isize) -> Self { Instance(a) } }
struct Service { a: Instance }
impl Default for Service { fn default() -> Self { Service{ a: Instance(0) } } }
impl Service { #[inject(default(instance = Instance(4)), no_inject(instance))] pub fn new(instance: Instance) -> Self { Self { a: instance } } }
fn injectable(a: isize, b: &Instance) -> isize { a + b.0 }
fn main() { let provider = Arc::new(Instance(3)); let container = container![ ref provider, |: &| Ok(Instance(1)) ]; let instance = get!(&container, Instance).unwrap();
let result = call!(&container, injectable, kwargs = { b: &instance }).unwrap();
// isize::default() + Instance(1).0
assert_eq!(result, 1);
// 12 + Arc(Instance(3)).as_ref().0
let result = call!(&container, injectable, kwargs = { a: 12 }).unwrap();
assert_eq!(result, 15);
let service = get!(&container, Service).unwrap();
assert_eq!(service.a.0, 1); // 1 since value-provider returns Instance(1)
let container = container![]; // new container, no providers
let service = get!(&container, Service).unwrap();
assert_eq!(service.a.0, 4); // The injection specific default, resolved since no provider for Instance
let service = Service::default();
assert_eq!(service.a.0, 0); // The trivial default impl, untouched
} ```
The get!
macro with a container
resolves a type in order of: installed provider (1), calling the associated inject
function on a type (2), and lastly the Default
implementation by a blanket impl of the InjectExt
trait (3) by the default associated function resolution order.
The interaction with the Default
impl is to imitiate ergonomics in injector.
(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).
call!
macro behaves similiarily to get!
, but supports kwargs.
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.