From 336e2166e2ed31b72b8c48d6a8342623cd0d352f Mon Sep 17 00:00:00 2001 From: Mnwa Date: Mon, 21 Sep 2020 17:08:07 +0300 Subject: [PATCH] Update doc --- derive_di/README.md | 2 +- derive_di/src/lib.rs | 248 +++++++++++++++++++++++++++++++ derive_di_core/src/injectable.rs | 1 + derive_di_core/src/lib.rs | 1 + derive_di_macro/src/lib.rs | 3 + 5 files changed, 254 insertions(+), 1 deletion(-) diff --git a/derive_di/README.md b/derive_di/README.md index c9d5592..f13f507 100644 --- a/derive_di/README.md +++ b/derive_di/README.md @@ -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 { @@ -45,7 +46,6 @@ impl InjectableStruct { } } -#[derive(Container)] struct MyContainer { i_struct: InjectableStruct, } diff --git a/derive_di/src/lib.rs b/derive_di/src/lib.rs index 86c958b..af4e72c 100644 --- a/derive_di/src/lib.rs +++ b/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, +//! } +//! ``` +//! 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, +//! } +//! 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, +//! } +//! +//! 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; diff --git a/derive_di_core/src/injectable.rs b/derive_di_core/src/injectable.rs index 5640bc5..bb1e143 100644 --- a/derive_di_core/src/injectable.rs +++ b/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; } diff --git a/derive_di_core/src/lib.rs b/derive_di_core/src/lib.rs index 31e53af..0cb2792 100644 --- a/derive_di_core/src/lib.rs +++ b/derive_di_core/src/lib.rs @@ -1 +1,2 @@ +//! Traits for `derive_di` module. pub mod injectable; diff --git a/derive_di_macro/src/lib.rs b/derive_di_macro/src/lib.rs index 3ccf047..9a4a0cb 100644 --- a/derive_di_macro/src/lib.rs +++ b/derive_di_macro/src/lib.rs @@ -1,3 +1,4 @@ +//! Macro for dependency injection pattern realization extern crate proc_macro; use proc_macro::TokenStream; @@ -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); @@ -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);