Skip to content

Commit

Permalink
Update doc
Browse files Browse the repository at this point in the history
  • Loading branch information
Mnwa committed Sep 21, 2020
1 parent 40a57ac commit 336e216
Show file tree
Hide file tree
Showing 5 changed files with 254 additions and 1 deletion.
2 changes: 1 addition & 1 deletion derive_di/README.md
Expand Up @@ -32,6 +32,7 @@ That code, which will be generated for you
```rust
use derive_di::*;

#[derive(Default)]
struct InjectableStruct;
impl Injectable for InjectableStruct {
fn get_service() -> Self {
Expand All @@ -45,7 +46,6 @@ impl InjectableStruct {
}
}

#[derive(Container)]
struct MyContainer {
i_struct: InjectableStruct,
}
Expand Down
248 changes: 248 additions & 0 deletions derive_di/src/lib.rs
@@ -1,3 +1,251 @@
//! 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
//! ```rust
//! use derive_di::*;
//! #[injectable]
//! #[derive(Default)]
//! struct InjectableStruct;
//!
//! impl InjectableStruct {
//! fn get(&self) -> String {
//! "test".to_owned()
//! }
//! }
//!
//! #[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()
//! }
//! }
//!
//! impl InjectableStruct {
//! fn get(&self) -> String {
//! "test".to_owned()
//! }
//! }
//!
//! struct MyContainer {
//! i_struct: InjectableStruct,
//! }
//!
//! impl MyContainer {
//! pub fn get_i_struct(&self) -> &InjectableStruct {
//! &self.i_struct
//! }
//! pub fn get_mut_i_struct(&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
//! use derive_di::*;
//! #[injectable(factory => InjectableStruct {inner: "test".to_owned()})]
//! struct InjectableStruct {
//! inner: String,
//! }
//! ```
//! The `Injectable` will be look like this
//! ```rust
//! 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.
//! ```rust
//! 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
//! ```rust
//! 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.
//! ```rust
//! use derive_di::*;
//! #[injectable(factory => || InjectableStruct {inner: "test".to_owned()})]
//! struct InjectableStruct {
//! inner: String,
//! }
//! ```
//! The `Injectable` will be look like this
//! ```rust
//! 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.
//! ```rust
//! 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 the`MyContainer` will be looks like
//!
//! ```rust
//! 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.
//!
//! ```rust
//! 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();
//! container.set_i_struct(Box::from(GetterMock));
//!
//! assert_eq!("mocked", container.get_i_struct().get())
//! }
//! ```

extern crate derive_di_macro;

pub use derive_di_core::injectable::Injectable;
Expand Down
1 change: 1 addition & 0 deletions derive_di_core/src/injectable.rs
@@ -1,3 +1,4 @@
/// Injectable trait which used for `Default` trait implementation of derive `Container` macro.
pub trait Injectable: Sized {
fn get_service() -> Self;
}
1 change: 1 addition & 0 deletions derive_di_core/src/lib.rs
@@ -1 +1,2 @@
//! Traits for `derive_di` module.
pub mod injectable;
3 changes: 3 additions & 0 deletions derive_di_macro/src/lib.rs
@@ -1,3 +1,4 @@
//! Macro for dependency injection pattern realization
extern crate proc_macro;
use proc_macro::TokenStream;

Expand All @@ -6,6 +7,7 @@ use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::{parse_macro_input, Data, DeriveInput, Expr, PathSegment, Token, Type};

/// Derive `Container` macro, will be implement getters, setters and `Default` trait for the struct.
#[proc_macro_derive(Container, attributes(inject))]
pub fn derive_container_fn(input: TokenStream) -> TokenStream {
let derived_container = parse_macro_input!(input as DeriveInput);
Expand Down Expand Up @@ -80,6 +82,7 @@ pub fn derive_container_fn(input: TokenStream) -> TokenStream {
out.into()
}

/// Auto implementation of Injectable trait
#[proc_macro_attribute]
pub fn injectable(args: TokenStream, input: TokenStream) -> TokenStream {
let input = parse_macro_input!(input as DeriveInput);
Expand Down

0 comments on commit 336e216

Please sign in to comment.