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
#![feature(unsize)]
#![feature(min_specialization)]

//! Runtime dependency injection.
//!
//! Documentation is under construction!
//!
//! # Examples
//!
//! ## Basic dependency resolution
//!
//! As a user of type `A` we only care about getting an instance to use - the
//! life-cycle of `A` and its dependencies remain hidden from us.
//!
//! ```
//! use dill::*;
//! use std::sync::Arc;
//!
//! #[component]
//! struct A {
//!     b: Arc<B>,  // An instance of `B` will be resolved and injected when requesting `A`
//! }
//!
//! impl A {
//!     fn foo(&self) -> String {
//!         format!("a::{}", self.b.bar())
//!     }
//! }
//!
//! #[component]
//! struct B;
//!
//! impl B {
//!     fn bar(&self) -> String {
//!         format!("b")
//!     }
//! }
//!
//! let catalog = CatalogBuilder::new()
//!   .add::<A>()
//!   .add::<B>()
//!   .build();
//!
//! let a = catalog.get_one::<A>().unwrap();
//! assert_eq!(a.foo(), "a::b");
//! ```
//!
//! ## Using trait objects (aka Interfaces)
//!
//! Every type can be associated with multiple traits that it implements using
//! [`CatalogBuilder::bind()`] method, allowing dynamically picking best
//! implementation to use (e.g. based on config) or even using multiple
//! implementations at once (e.g. plugins).
//!
//! ```
//! use dill::*;
//! use std::sync::Arc;
//!
//! // An interface that has two implementations below
//! trait A: Send + Sync {
//!     fn foo(&self) -> String;
//! }
//!
//! #[component]
//! struct AImpl1;
//! impl A for AImpl1 {
//!     fn foo(&self) -> String {
//!         format!("aimpl1")
//!     }
//! }
//!
//! #[component]
//! struct AImpl2;
//! impl A for AImpl2 {
//!     fn foo(&self) -> String {
//!         format!("aimpl2")
//!     }
//! }
//!
//! let catalog = CatalogBuilder::new()
//!   .add::<AImpl1>()
//!   .bind::<dyn A, AImpl1>()
//!   .add::<AImpl2>()
//!   .bind::<dyn A, AImpl2>()
//!   .build();
//!
//! // AllOf<T> is a DependencySpec that returns instances of all types that implement trait T
//! let ays = catalog.get::<AllOf<dyn A>>().unwrap();
//!
//! let mut foos: Vec<_> = ays.iter().map(|a| a.foo()).collect();
//! foos.sort(); // Order is undefined
//!
//! assert_eq!(foos, vec!["aimpl1".to_owned(), "aimpl2".to_owned()]);
//! ```
//!
//! ## Controlling lifetimes with Scopes
//!
//! The life-cycle of a type is no longer controlled by the user of a type.
//! Author of type `A` below can choose whether `A` should be created per call
//! ([`Transient`]) or reused by all clients ([`Singleton`]).
//!
//! ```
//! use dill::*;
//!
//! #[component]
//! #[scope(Singleton)]
//! struct A {
//!     // Needed for compiler not to optimize type out
//!     name: String,
//! }
//!
//! impl A {
//!     fn test(&self) -> String {
//!         format!("a::{}", self.name)
//!     }
//! }
//!
//! let cat = CatalogBuilder::new()
//!     .add::<A>()
//!     .add_value("foo".to_owned())
//!     .build();
//!
//! let inst1 = cat.get::<OneOf<A>>().unwrap();
//! let inst2 = cat.get::<OneOf<A>>().unwrap();
//!
//! // Expecting Singleton scope to return same instance
//! assert_eq!(
//!     inst1.as_ref() as *const A,
//!     inst2.as_ref() as *const A
//! );
//! ```
//!
//! ## Parametrizing builders
//!
//! Builders can be parametrized during the registration process for convenience
//! (e.g. with values read from configuration).
//!
//! ```
//! use dill::*;
//!
//! #[component]
//! #[scope(Singleton)]
//! struct ConnectionPool {
//!     host: String,
//!     port: i32,
//! }
//!
//! impl ConnectionPool {
//!     fn url(&self) -> String {
//!         format!("http://{}:{}", self.host, self.port)
//!     }
//! }
//!
//! let cat = CatalogBuilder::new()
//!     .add_builder(
//!         ConnectionPool::builder()
//!             .with_host("foo".to_owned())
//!             .with_port(8080),
//!     )
//!     .build();
//!
//! let inst = cat.get::<OneOf<ConnectionPool>>().unwrap();
//! assert_eq!(inst.url(), "http://foo:8080");
//! ```

pub use dill_impl::*;

mod builder;
pub use builder::*;

mod catalog_builder;
pub use catalog_builder::*;

mod catalog;
pub use catalog::*;

mod errors;
pub use errors::*;

mod specs;
pub use specs::*;

mod scopes;
pub use scopes::*;

mod typecast_builder;
pub use typecast_builder::*;