Crates.io | inject-macro |
lib.rs | inject-macro |
version | 0.1.1 |
source | src |
created_at | 2020-08-14 15:57:11.134301 |
updated_at | 2020-08-21 22:19:44.214151 |
description | Experimental IOC library for Rust, procedural macros |
homepage | |
repository | https://github.com/tobni/inject-rs |
max_upload_size | |
id | 276611 |
size | 33,248 |
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::*;
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::*;
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::*;
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 syntax
use ::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
trait
use ::inject::*;
#[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:
create_object!
flavored macro.#[inject]
support Struct attribute notation with #[inject(..)]
for individual struct fields.default
and no_inject
story less annoying.