aboutsummaryrefslogtreecommitdiff
path: root/src/lib.rs
blob: d93acc8e13851d2b71ae0117a79db29bdb6d8f08 (plain)
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
#![cfg_attr(feature = "factory", feature(unboxed_closures, tuple_trait))]
#![cfg_attr(doc_cfg, feature(doc_cfg))]
#![deny(clippy::all)]
#![deny(clippy::pedantic)]
#![allow(clippy::module_name_repetitions)]
#![deny(missing_docs)]

//! Syrette
//!
//! Syrette is a framework for utilizing inversion of control & dependency injection.
//!
//! # Example
//! ```
//! use std::error::Error;
//!
//! use syrette::ptr::TransientPtr;
//! use syrette::{injectable, DIContainer};
//!
//! trait IWeapon
//! {
//!     fn deal_damage(&self, damage: i32);
//! }
//!
//! struct Sword {}
//!
//! #[injectable(IWeapon)] // Makes Sword injectable with a interface of IWeapon
//! impl Sword
//! {
//!     fn new() -> Self
//!     {
//!         Self {}
//!     }
//! }
//!
//! impl IWeapon for Sword
//! {
//!     fn deal_damage(&self, damage: i32)
//!     {
//!         println!("Sword dealt {} damage!", damage);
//!     }
//! }
//!
//! trait IWarrior
//! {
//!     fn fight(&self);
//! }
//!
//! struct Warrior
//! {
//!     weapon: TransientPtr<dyn IWeapon>,
//! }
//!
//! #[injectable(IWarrior)] // Makes Warrior injectable with a interface of IWarrior
//! impl Warrior
//! {
//!     fn new(weapon: TransientPtr<dyn IWeapon>) -> Self
//!     {
//!         Self { weapon }
//!     }
//! }
//!
//! impl IWarrior for Warrior
//! {
//!     fn fight(&self)
//!     {
//!         self.weapon.deal_damage(30);
//!     }
//! }
//!
//! fn main() -> Result<(), Box<dyn Error>>
//! {
//!     let mut di_container = DIContainer::new();
//!
//!     // Creates a binding of the interface IWeapon to the concrete type Sword
//!     di_container.bind::<dyn IWeapon>().to::<Sword>()?;
//!
//!     // Creates a binding of the interface IWarrior to the concrete type Warrior
//!     di_container.bind::<dyn IWarrior>().to::<Warrior>()?;
//!
//!     // Create a transient IWarrior with all of its dependencies automatically injected
//!     let warrior = di_container.get::<dyn IWarrior>()?.transient()?;
//!
//!     warrior.fight();
//!
//!     println!("Warrior has fighted");
//!
//!     Ok(())
//! }
//! ```

pub mod dependency_history;
pub mod di_container;
pub mod errors;
pub mod interfaces;
pub mod ptr;

#[cfg(feature = "async")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "async")))]
pub mod future;

#[cfg(feature = "async")]
#[cfg_attr(doc_cfg, doc(cfg(feature = "async")))]
pub use di_container::asynchronous::AsyncDIContainer;
pub use di_container::blocking::DIContainer;
pub use syrette_macros::{declare_interface, injectable, named};

#[doc(hidden)]
pub mod private;

mod provider;
mod util;

#[cfg(feature = "factory")]
mod castable_factory;

#[cfg(feature = "factory")]
mod any_factory;

#[cfg(test)]
#[cfg(not(tarpaulin_include))]
mod test_utils;

/// Shortcut for creating a DI container binding for a injectable without a declared
/// interface.
///
/// This will declare a interface for the implementation.
///
/// Useful for when the implementation or the interface is generic.
///
/// # Arguments
/// {interface} => {implementation}, {DI container variable name}
///
/// # Examples
/// ```
/// # use syrette::{di_container_bind, DIContainer, injectable};
/// #
/// # trait INinja {}
/// #
/// # struct Ninja {}
/// #
/// # #[injectable]
/// # impl Ninja
/// # {
/// #     fn new() -> Self
/// #     {
/// #         Self {}
/// #     }
/// # }
/// #
/// # impl INinja for Ninja {}
/// #
/// let mut di_container = DIContainer::new();
///
/// di_container_bind!(INinja => Ninja, di_container);
/// ```
#[cfg(not(tarpaulin_include))]
#[macro_export]
macro_rules! di_container_bind {
    ($interface: path => $implementation: ty, $di_container: ident) => {
        $di_container.bind::<dyn $interface>().to::<$implementation>().unwrap();

        syrette::declare_interface!($implementation -> $interface);
    };
}