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
226
227
228
229
230
231
232
233
234
//! # A tiny dependency injection library for Rust.
//!
//! This library provides a simple way to inject dependencies into structs.
//! Injectiny is *not* a framework, but can be used inside one. Please refer to the README.md
//! for an example of how to use it.
//!
//! # Installation
//!
//! To use Injectiny, make sure to include both the `injectiny` and `injectiny_proc_macro` crates.
//!
//! ```ignore
//! cargo add injectiny
//! cargo add injectiny_proc_macro
//! ```
//!
//! # Example: Manual Injection
//!
//! ```
//!
//! use std::cell::RefCell;
//! use std::rc::Rc;
//! use injectiny::{Injected, Injectable};
//! use injectiny_proc_macro::injectable;
//!
//! // Model is an enum defining all the fields that can be injected
//! #[derive(Clone)]
//! enum Model {
//! Name(Rc<RefCell<String>>), // non-clonable objects should be wrapped in Rc<RefCell<T>>
//! Age(u32)
//! }
//!
//! // The #[injectable] attribute macro generates an implementation of the Injectable trait for
//! // the given Model enum. In real situations, this could be one of several controllers, views, ...
//! #[injectable(Model)]
//! #[derive(Default)]
//! struct Injectee
//! {
//! // The #[inject] attribute macro marks a field as injectable with the enum member. The field
//! // type must be Injected<T>, where T is the type of the enum member's value.
//! #[inject(Model::Name)]
//! name: Injected<Rc<RefCell<String>>>,
//!
//! #[inject(Model::Age)]
//! age: Injected<u32>
//! }
//!
//! // This would represent a model
//! let name = Rc::new(RefCell::new("Patje".to_string()));
//! let age = 25;
//!
//! // This could be one of many views
//! let mut injectee: Injectee = Default::default();
//! injectee.inject(Model::Name(Rc::clone(&name)));
//! injectee.inject(Model::Age(age));
//!
//! // The injected fields can be accessed like normal references
//! assert_eq!(&*injectee.name.borrow(), "Patje");
//! assert_eq!(*injectee.age, 25);
//! ```
//!
//! # Example: Injection using Injector
//!
//! For larger projects, the manual approach can become cumbersome. The `Injector` struct can be used
//! to make injecting dependencies more ergonomic.
//!
//! ```
//! use std::cell::RefCell;
//! use std::rc::Rc;
//! use std::sync::{Arc, Mutex};
//! use injectiny::{Injected, Injectable, Injector};
//! use injectiny_proc_macro::injectable;
//!
//! // Model is an enum defining all the fields that can be injected
//! #[derive(Clone)]
//! enum Model {
//! Name(Rc<RefCell<String>>), // non-clonable objects should be wrapped in Rc<RefCell<T>>
//! Age(u32),
//! Other(Rc<RefCell<Injectee>>)
//! }
//!
//! // The #[injectable] attribute macro generates an implementation of the Injectable trait for
//! // the given Model enum. In real situations, this could be one of several controllers, views, ...
//! #[injectable(Model)]
//! #[derive(Default)]
//! struct Injectee
//! {
//! // The #[inject] attribute macro marks a field as injectable with the enum member. The field
//! // type must be Injected<T>, where T is the type of the enum member's value.
//! #[inject(Model::Name)]
//! name: Injected<Rc<RefCell<String>>>,
//!
//! #[inject(Model::Age)]
//! age: Injected<u32>
//! }
//!
//! #[injectable(Model)]
//! #[derive(Default)]
//! struct OtherInjectee
//! {
//! // we can also inject other injected models
//! #[inject(Model::Other)]
//! other: Injected<Rc<RefCell<Injectee>>>,
//! }
//!
//! // This would represent a model
//! let name = Rc::new(RefCell::new("Patje".to_string()));
//! let age = 25;
//!
//! // we're going to inject injectee2, so wrap it in an Rc<Refcell<>>, or an Arc<Mutex/RwLock>
//! let mut injectee1: Rc<RefCell<Injectee>> = Default::default();
//! let mut injectee2: OtherInjectee = Default::default();
//!
//! // the order of inject and to calls does not matter
//! let injector = Injector::new()
//! // inject sources. These need to be functions because usually, we're cloning a smart pointer or something
//! .inject(&|| Model::Name(Rc::clone(&name)))
//! .inject(&|| Model::Age(age))
//! .inject(&|| Model::Other(Rc::clone(&injectee1)))
//! // inject targets
//! // behind a RefCell, need to convert to ref
//! .to(&mut *injectee1.borrow_mut())
//! .to(&mut injectee2);
//!
//! // The injected fields can be accessed like normal references
//! assert_eq!(&*injectee1.borrow().name.borrow(), "Patje");
//! assert_eq!(*injectee1.borrow().age, 25);
//!
//! // making sure the injected Injectee is the same
//! let injected = injectee2.other.borrow();
//! assert_eq!(&*injected.name.borrow(), "Patje");
//! assert_eq!(*injected.age, 25);
//! ```
extern crate injectiny_proc_macro;
use ;
///
/// Injected is a wrapper around a value that can be injected into a struct. All injected members
/// must be wrapped by this type.
///
///
/// Injector is a convenience struct that can making injecting things a bit more ergonomic.
///