Expand description
Rust macro to automatically implement the dependency injection pattern for arbitrary structs.
A simple #[derive(Container)]
will generate new getters and setters for every field of your struct.
Also, the Container will implement the Default
trait, where will inject every field with Injectable
trait.
This makes the possible to mock any dyn Trait
field in your container.
§Quick start
Just add the derive_di
to you Cargo.toml and import the deps.
§Simple example
use derive_di::*;
#[injectable]
#[derive(Default)]
struct InjectableStruct;
#[derive(Container)]
struct MyContainer {
i_struct: InjectableStruct,
}
That code, which will be generated for you
use derive_di::*;
#[derive(Default)]
struct InjectableStruct;
impl Injectable for InjectableStruct {
fn get_service() -> Self {
Default::default()
}
}
struct MyContainer {
i_struct: InjectableStruct,
}
impl MyContainer {
pub fn get_i_struct(&self) -> &InjectableStruct {
&self.i_struct
}
pub fn get_i_struct_mut(&mut self) -> &mut InjectableStruct {
&mut self.i_struct
}
pub fn set_i_struct(&mut self, i_struct: InjectableStruct) {
self.i_struct = i_struct
}
}
impl Default for MyContainer {
fn default() -> Self {
Self {
i_struct: Injectable::get_service()
}
}
}
§Additional features
§Factory
You can pass any factory to the injectable
macro for building you struct.
§Factory struct
You can build you struct inside injectable
macro.
use derive_di::*;
#[injectable(factory => InjectableStruct {inner: "test".to_owned()})]
struct InjectableStruct {
inner: String,
}
The Injectable
will be look like this
use derive_di::*;
struct InjectableStruct {
inner: String,
}
impl Injectable for InjectableStruct {
fn get_service() -> Self {
InjectableStruct {inner: "test".to_owned()}
}
}
§Factory fn
You can build you struct inside injectable
macro with factory method.
use derive_di::*;
fn factory_struct() -> InjectableStruct {
InjectableStruct {
inner: "test".to_owned(),
}
}
#[injectable(factory => factory_struct())]
struct InjectableStruct {
inner: String,
}
The Injectable
will be look like this
use derive_di::*;
fn factory_struct() -> InjectableStruct {
InjectableStruct {
inner: "test".to_owned(),
}
}
struct InjectableStruct {
inner: String,
}
impl Injectable for InjectableStruct {
fn get_service() -> Self {
factory_struct()
}
}
§Factory closure
You can build you struct inside injectable
macro with factory closure.
use derive_di::*;
#[injectable(factory => || InjectableStruct {inner: "test".to_owned()})]
struct InjectableStruct {
inner: String,
}
The Injectable
will be look like this
use derive_di::*;
struct InjectableStruct {
inner: String,
}
impl Injectable for InjectableStruct {
fn get_service() -> Self {
(|| InjectableStruct {inner: "test".to_owned()})()
}
}
§Auto injecting a structs to the dyn Trait
container fields
With the inject
macro, you can easy to solve dyn Trait
fields in tou container.
use derive_di::*;
#[injectable(factory => InjectableStruct)]
struct InjectableStruct;
trait Getter {
fn get(&self) -> String;
}
impl Getter for InjectableStruct {
fn get(&self) -> String {
"test".to_owned()
}
}
#[derive(Container)]
struct MyContainer {
#[inject(InjectableStruct)]
i_struct: Box<dyn Getter>,
}
The Default
impl of theMyContainer
will be looks like
use derive_di::*;
#[injectable(factory => InjectableStruct)]
struct InjectableStruct;
trait Getter {
fn get(&self) -> String;
}
impl Getter for InjectableStruct {
fn get(&self) -> String {
"test".to_owned()
}
}
struct MyContainer {
i_struct: Box<dyn Getter>,
}
impl Default for MyContainer {
fn default() -> Self {
Self {
i_struct: Box::from(InjectableStruct::get_service())
}
}
}
§Mocks
You can combine the dyn Trait
fields and setters in your container
and mock any logic for simple testing.
use derive_di::*;
#[injectable(factory => || InjectableStruct)]
struct InjectableStruct;
trait Getter {
fn get(&self) -> String;
}
impl Getter for InjectableStruct {
fn get(&self) -> String {
"test".to_owned()
}
}
struct GetterMock;
impl Getter for GetterMock {
fn get(&self) -> String {
"mocked".to_owned()
}
}
#[derive(Container)]
struct MyContainer {
#[inject(InjectableStruct)]
i_struct: Box<dyn Getter>,
}
fn main() {
let mut container = MyContainer::default();
assert_eq!("test", container.get_i_struct().get());
container.set_i_struct(Box::from(GetterMock));
assert_eq!("mocked", container.get_i_struct().get())
}
Traits§
- Injectable trait which used for
Default
trait implementation of deriveContainer
macro.
Attribute Macros§
- Auto implementation of Injectable trait
Derive Macros§
- Derive
Container
macro, will be implement getters, setters andDefault
trait for the struct.