# Dependency Injection pattern derive [![](https://github.com/Mnwa/derive_di/workflows/build/badge.svg?branch=master)](https://github.com/Mnwa/derive_di/actions?query=workflow%3Abuild) [![](https://docs.rs/derive_di/badge.svg)](https://docs.rs/derive_di/) [![](https://img.shields.io/crates/v/derive_di.svg)](https://crates.io/crates/derive_di) [![](https://img.shields.io/crates/d/derive_di.svg)](https://crates.io/crates/derive_di) 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. ## Simple example ```rust use derive_di::*; #[injectable] #[derive(Default)] struct InjectableStruct; #[derive(Container)] struct MyContainer { i_struct: InjectableStruct, } ``` That code, which will be generated for you ```rust 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. ```rust #[injectable(factory => InjectableStruct {inner: "test".to_owned()})] struct InjectableStruct { inner: String, } ``` The `Injectable` will be look like this ```rust 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. ```rust fn factory_struct() -> InjectableStruct { InjectableStruct { inner: "test".to_owned(), } } #[injectable(factory => factory_struct())] struct InjectableStruct { inner: String, } ``` The `Injectable` will be look like this ```rust impl Injectable for InjectableStruct { fn get_service() -> Self { factory_struct() } } ``` #### Factory closure You can build you struct inside `injectable` macro with factory closure. ```rust #[injectable(factory => || InjectableStruct {inner: "test".to_owned()})] struct InjectableStruct { inner: String, } ``` The `Injectable` will be look like this ```rust 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. ```rust #[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, } ``` The `Default` impl of the`MyContainer` will be looks like ```rust 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. ```rust #[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, } 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()) } ```