1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
// <click to unfold doc>
    //! # What is Dependency Injection (aka. Dependency Inversion)?
    //! 
    //! The idea behind inversion of control is that, rather than tie the classes in your application together and let classes “new up” their dependencies, you switch it around so dependencies are instead passed in during class construction. It's one of the 5 core principles of [SOLID programming](https://en.wikipedia.org/wiki/SOLID_(object-oriented_design))
    //!
    //! If you want to read more on that:
    //! <ul>
    //! <li> [Martin Fowler has an excellent article explaining dependency injection/inversion of control](http://martinfowler.com/articles/injection.html)
    //! <li> [Wikipedia article on dependency inversion principle](https://en.wikipedia.org/wiki/Dependency_inversion_principle)
    //! </ul>
    //! 
    //! # Getting started
    //! ## Structure your application
    //! Start by writing a classical application with struct & types (in homage to [AutoFac] (https://autofac.org/) I ported their classical "getting started" example).
    //! Code excerpts are used below to illustrate this little guide, the complete example is available [here](https://github.com/bgbahoue/he-di/blob/master/examples/autofac/src/main.rs).
    //! 
    //! ```rust
    //! trait IOutput {
    //!     fn write(&self, content: String);
    //! }
    //! 
    //! struct ConsoleOutput {
    //!     prefix: String,
    //!     other_param: usize,
    //! }
    //! 
    //! impl IOutput for ConsoleOutput {
    //!     fn write(&self, content: String) {
    //!         println!("{} #{} {}", self.prefix, self.other_param, content);
    //!     }
    //! }
    //! 
    //! trait IDateWriter {
    //!     fn write_date(&self);
    //! }
    //! 
    //! struct TodayWriter {
    //!     output: Box<IOutput>,
    //!     today: String,
    //!     year: String,
    //! }
    //! 
    //! impl IDateWriter for TodayWriter {
    //!     fn write_date(&self) {
    //!        let mut content = "Today is ".to_string();
    //!        content.push_str(self.today.as_str());
    //!        content.push_str(" ");
    //!        content.push_str(self.year.to_string().as_str());
    //!        self.output.write(content);
    //!     }
    //! }
    //! ```
    //! 
    //! ## Mark structs as Component
    //! A component is an expression or other bit of code that exposes one or more services and can take in other dependencies.
    //! 
    //! In our example, we have 2 components:
    //! 
    //! - `TodayWriter` of type `IDateWriter` 
    //! - `ConsoleOutput` of type `IOutput` 
    //! 
    //! To be able to identify them as components [he_di](https://crates.io/crates/he_di) exposes a `#[derive()]` macro (though the [he_di_derive](https://crates.io/crates/he_di_derive) crate).
    //! It is simply done using the following attributes:
    //!
    //! ```rust,ignore
    //! #[derive(Component)] // <--- mark as a Component
    //! #[interface(IOutput)] // <--- specify the type of this Component
    //! struct ConsoleOutput {
    //!     prefix: String,
    //!     other_param: usize,
    //! }
    //! ```
    //! 
    //! In the current version, you alos need to specify the type of your Component using the `#[interface()]` attribute.
    //! 
    //! ## Express dependencies
    //! Some components can have dependencies to other components, which allows the DI logic to also inject these components with another Component.
    //! 
    //! In our example, `ConsoleOuput` is a Component with no dependency and `TodayWriter` a Component with a dependency to a `IOutput` Component. 
    //! 
    //! To express this dependency, use the `#[inject]` attribute within your struct to flag the property and declare the property as a [trait object](https://doc.rust-lang.org/book/first-edition/trait-objects.html).
    //!
    //! In our example:
    //! 
    //! ```rust,ignore
    //! #[macro_use] extern crate he_di_derive;
    //!
    //! #[derive(Component)] // <--- mark a struct as a Component that can be registered & resolved
    //! #[interface(IDateWriter)] // <--- specify which interface it implements
    //! struct TodayWriter {
    //!     #[inject] // <--- flag 'output' as a property which can be injected
    //!     output: Box<IOutput>, // <--- trait object using the interface `IOutput`
    //!     today: String,
    //!     year: usize,
    //! }
    //! ```
    //! 
    //! ## Application startup
    //! At application startup, you need to create a [ContainerBuilder](struct.ContainerBuilder.html) and register your components with it. 
    //! 
    //! In our example, we register `ConsoleOutput` and `TodayWriter` with a `ContainerBuilder` doing something like this:
    //! 
    //! ```rust,ignore
    //! // Create your builder.
    //! let mut builder = ContainerBuilder::new();
    //! 
    //! builder
    //!     .register::<ConsoleOutput>()
    //!     .as_type::<IOutput>();
    //! 
    //! builder
    //!     .register::<TodayWriter>()
    //!     .as_type::<IDateWriter>();
    //! 
    //! // Create a Container holding the DI magic
    //! let mut container = builder.build().unwrap();
    //! ```
    //! 
    //! The `Container` reference is what you will use to resolve types & components later. It can then be stored as you see fit.
    //! 
    //! ## Application execution
    //! During application execution, you’ll need to make use of the components you registered. You do this by resolving them from a `Container` with one of the 3 `resolve()` methods.
    //! 
    //! ### Passing parameters
    //! In most cases you need to pass parameters to a Component. This can be done either when registring a Component into a [ContainerBuilder](struct.ContainerBuilder.html) or when resolving a Component from a [Container](struct.Container.html).
    //!
    //! You can register parameters either using their property name or their property type. In the later case, you need to ensure that it is unique.
    //! 
    //! #### When registering components
    //! Passing parameters at registration time is done using the `with_named_parameter()` or `with_typed_parameter()` chained methods like that:
    //!
    //! ```rust,ignore
    //! builder
    //!     .register::<ConsoleOutput>()
    //!     .as_type::<IOutput>()
    //!     .with_named_parameter("prefix", "PREFIX >".to_string())
    //!     .with_typed_parameter::<usize>(117 as usize);
    //! ```
    //! 
    //! #### When resolving components
    //! Passing parameters at resolve time uses the same `with_named_parameter()` or `with_typed_parameter()` methods from your [Container](struct.Container.html) instance.
    //!
    //! For our sample app, we created a `write_date()` method to resolve the writer from a Container and illustrate how to pass parameters with its name or type:
    //!
    //! ```rust,ignore
    //! fn write_date(container: &mut Container) {
    //!     let writer = container
    //!         .with_typed_parameter::<IDateWriter, String>("June 20".to_string())
    //!         .with_named_parameter::<IDateWriter, usize>("year", 2017 as usize)
    //!         .resolve::<IDateWriter>()
    //!         .unwrap();
    //!     writer.write_date();
    //! }
    //! ```
    //! 
    //! Now when you run your program...
    //! 
    //! - The `write_date()` method asks he_di for an `IDateWriter`.
    //! - he_di sees that `IDateWriter` maps to `TodayWriter` so starts creating a `TodayWriter`.
    //! - he_di sees that the `TodayWriter` needs an `IOutput` in its constructor.
    //! - he_di sees that `IOutput` maps to `ConsoleOutput` so creates a new `ConsoleOutput` instance.
    //! - Since `ConsoleOutput` doesn't have any more dependency, it uses this instance to finish constructing the `TodayWriter`.
    //! - he_di returns the fully-constructed `TodayWriter` for `write_date()` to use.
    //! 
    //! Later, if we wanted our application to write a different date, we would just have to implement a different `IDateWriter` and then change the registration at app startup. We won’t have to change any other classes. Yay, inversion of control!
    //! 
    //! ## Roadmap
    //! The current implementation of this crate is still WIP. A few identified usefull to know limitations (being further explorer) are:
    //!
    //! - `#[derive(Component)]` should be tested against complex cases & more tests are to be written (e.g, struct with lifetime, generics, ...)
    //! - we should support closures as a way to create parameters (at register or resolve time)

#![feature(core_intrinsics)] // used in container/map_container.rs for error logging purpose

// Linting
#![allow(unknown_lints)] // in case clippy is not use to compile

// Clippy
#![cfg_attr(feature="clippy", feature(plugin))]
#![cfg_attr(feature="clippy", plugin(clippy))]
#![deny(unused_must_use)]
#![allow(new_without_default_derive)]

// Reexport of [anymap](https://crates.io/crates/anymap) 
#[doc(hidden)]
pub extern crate anymap;
#[macro_use] extern crate log;
extern crate unsafe_any;
extern crate he_di_internals;
extern crate fluent_validator;

// Hide modules from public API
pub mod container;
#[doc(hidden)]
pub mod consts;
#[doc(hidden)]
pub mod component;
pub mod parameter;

// Shortcut to main types / traits
pub use container::Container;
pub use container::ContainerBuilder;

#[doc(hidden)]
pub use component::Built;
#[doc(hidden)]
pub use component::Component;
#[doc(hidden)]
pub use component::ComponentBuilder;

// Reexport Error type from he_di_internals
pub use he_di_internals::error::Error;

// Main DI Result type mapping
#[doc(hidden)]
pub mod result {
    /// Alias for a `Result` with the error type [he_di::Error](enum.Error.html)
    pub type Result<T> = ::std::result::Result<T, super::he_di_internals::error::Error>;
}
pub use result::Result;

// For tests
#[cfg(test)]
#[allow(unused_imports)]
#[macro_use] extern crate he_di_derive;