1use super::{names_equal, Builder};
2use crate::{Configure, PostConfigure, Ref, Value};
3use cfg_if::cfg_if;
4use di::{singleton_factory, transient_factory, Ref as Svc};
5use std::marker::PhantomData;
6
7macro_rules! configure_impl {
8 (($($bounds:tt)+), _Configure, []) => {
10 struct _Configure<TOptions, TAction> {
11 name: String,
12 action: TAction,
13 _type: PhantomData<TOptions>,
14 }
15
16 impl<TOptions, TAction> Configure<TOptions> for _Configure<TOptions, TAction>
17 where
18 TOptions: Value,
19 TAction: Fn(&mut TOptions) + $($bounds)+,
20 {
21 fn run(&self, name: &str, options: &mut TOptions) {
22 if names_equal(&self.name, name) {
23 (self.action)(options)
24 }
25 }
26 }
27
28 impl<TOptions, TAction> PostConfigure<TOptions> for _Configure<TOptions, TAction>
29 where
30 TOptions: Value,
31 TAction: Fn(&mut TOptions) + $($bounds)+,
32 {
33 fn run(&self, name: &str, options: &mut TOptions) {
34 if names_equal(&self.name, name) {
35 (self.action)(options)
36 }
37 }
38 }
39 };
40 (($($bounds:tt)+), $struct_name:ident, [$(($dep_generic:ident, $dep_field:ident)),+]) => {
42 struct $struct_name<TOptions, TAction, $($dep_generic),+> {
43 name: String,
44 action: Ref<TAction>,
45 $($dep_field: Svc<$dep_generic>,)+
46 _type: PhantomData<TOptions>,
47 }
48
49 impl<TOptions, TAction, $($dep_generic),+> Configure<TOptions>
50 for $struct_name<TOptions, TAction, $($dep_generic),+>
51 where
52 TOptions: Value,
53 TAction: Fn(&mut TOptions, $(Svc<$dep_generic>),+) + $($bounds)+,
54 $($dep_generic: Value,)+
55 {
56 fn run(&self, name: &str, options: &mut TOptions) {
57 if names_equal(&self.name, name) {
58 (self.action)(options, $(self.$dep_field.clone()),+)
59 }
60 }
61 }
62
63 impl<TOptions, TAction, $($dep_generic),+> PostConfigure<TOptions>
64 for $struct_name<TOptions, TAction, $($dep_generic),+>
65 where
66 TOptions: Value,
67 TAction: Fn(&mut TOptions, $(Svc<$dep_generic>),+) + $($bounds)+,
68 $($dep_generic: Value,)+
69 {
70 fn run(&self, name: &str, options: &mut TOptions) {
71 if names_equal(&self.name, name) {
72 (self.action)(options, $(self.$dep_field.clone()),+)
73 }
74 }
75 }
76 };
77}
78
79macro_rules! configure_builder_method {
81 (($($bounds:tt)+), $method:ident, $post_method:ident, $struct_name:ident, ($d1:ident, $f1:ident)) => {
82 pub fn $method<F, $d1>(self, setup: F) -> Self
88 where
89 F: Fn(&mut T, Svc<$d1>) + $($bounds)+,
90 $d1: $($bounds)+,
91 {
92 let action = Ref::new(setup);
93 let name = self.name.clone();
94
95 self.services.add(transient_factory(move |sp| {
96 let config: Ref<dyn Configure<T>> = Ref::new($struct_name {
97 name: name.clone(),
98 action: action.clone(),
99 $f1: sp.get_required::<$d1>(),
100 _type: PhantomData,
101 });
102 config
103 }));
104
105 self
106 }
107
108 pub fn $post_method<F, $d1>(self, setup: F) -> Self
114 where
115 F: Fn(&mut T, Svc<$d1>) + $($bounds)+,
116 $d1: $($bounds)+,
117 {
118 let action = Ref::new(setup);
119 let name = self.name.clone();
120
121 self.services.add(transient_factory(move |sp| {
122 let config: Ref<dyn PostConfigure<T>> = Ref::new($struct_name {
123 name: name.clone(),
124 action: action.clone(),
125 $f1: sp.get_required::<$d1>(),
126 _type: PhantomData,
127 });
128 config
129 }));
130
131 self
132 }
133 };
134 (($($bounds:tt)+), $method:ident, $post_method:ident, $struct_name:ident, ($d1:ident, $f1:ident), ($d2:ident, $f2:ident)) => {
135 pub fn $method<F, $d1, $d2>(self, setup: F) -> Self
141 where
142 F: Fn(&mut T, Svc<$d1>, Svc<$d2>) + $($bounds)+,
143 $d1: $($bounds)+,
144 $d2: $($bounds)+,
145 {
146 let action = Ref::new(setup);
147 let name = self.name.clone();
148
149 self.services.add(transient_factory(move |sp| {
150 let config: Ref<dyn Configure<T>> = Ref::new($struct_name {
151 name: name.clone(),
152 action: action.clone(),
153 $f1: sp.get_required::<$d1>(),
154 $f2: sp.get_required::<$d2>(),
155 _type: PhantomData,
156 });
157 config
158 }));
159
160 self
161 }
162
163 pub fn $post_method<F, $d1, $d2>(self, setup: F) -> Self
169 where
170 F: Fn(&mut T, Svc<$d1>, Svc<$d2>) + $($bounds)+,
171 $d1: $($bounds)+,
172 $d2: $($bounds)+,
173 {
174 let action = Ref::new(setup);
175 let name = self.name.clone();
176
177 self.services.add(transient_factory(move |sp| {
178 let config: Ref<dyn PostConfigure<T>> = Ref::new($struct_name {
179 name: name.clone(),
180 action: action.clone(),
181 $f1: sp.get_required::<$d1>(),
182 $f2: sp.get_required::<$d2>(),
183 _type: PhantomData,
184 });
185 config
186 }));
187
188 self
189 }
190 };
191 (($($bounds:tt)+), $method:ident, $post_method:ident, $struct_name:ident, ($d1:ident, $f1:ident), ($d2:ident, $f2:ident), ($d3:ident, $f3:ident)) => {
192 pub fn $method<F, $d1, $d2, $d3>(self, setup: F) -> Self
198 where
199 F: Fn(&mut T, Svc<$d1>, Svc<$d2>, Svc<$d3>) + $($bounds)+,
200 $d1: $($bounds)+,
201 $d2: $($bounds)+,
202 $d3: $($bounds)+,
203 {
204 let action = Ref::new(setup);
205 let name = self.name.clone();
206
207 self.services.add(transient_factory(move |sp| {
208 let config: Ref<dyn Configure<T>> = Ref::new($struct_name {
209 name: name.clone(),
210 action: action.clone(),
211 $f1: sp.get_required::<$d1>(),
212 $f2: sp.get_required::<$d2>(),
213 $f3: sp.get_required::<$d3>(),
214 _type: PhantomData,
215 });
216 config
217 }));
218
219 self
220 }
221
222 pub fn $post_method<F, $d1, $d2, $d3>(self, setup: F) -> Self
228 where
229 F: Fn(&mut T, Svc<$d1>, Svc<$d2>, Svc<$d3>) + $($bounds)+,
230 $d1: $($bounds)+,
231 $d2: $($bounds)+,
232 $d3: $($bounds)+,
233 {
234 let action = Ref::new(setup);
235 let name = self.name.clone();
236
237 self.services.add(transient_factory(move |sp| {
238 let config: Ref<dyn PostConfigure<T>> = Ref::new($struct_name {
239 name: name.clone(),
240 action: action.clone(),
241 $f1: sp.get_required::<$d1>(),
242 $f2: sp.get_required::<$d2>(),
243 $f3: sp.get_required::<$d3>(),
244 _type: PhantomData,
245 });
246 config
247 }));
248
249 self
250 }
251 };
252 (($($bounds:tt)+), $method:ident, $post_method:ident, $struct_name:ident, ($d1:ident, $f1:ident), ($d2:ident, $f2:ident), ($d3:ident, $f3:ident), ($d4:ident, $f4:ident)) => {
253 pub fn $method<F, $d1, $d2, $d3, $d4>(self, setup: F) -> Self
259 where
260 F: Fn(&mut T, Svc<$d1>, Svc<$d2>, Svc<$d3>, Svc<$d4>) + $($bounds)+,
261 $d1: $($bounds)+,
262 $d2: $($bounds)+,
263 $d3: $($bounds)+,
264 $d4: $($bounds)+,
265 {
266 let action = Ref::new(setup);
267 let name = self.name.clone();
268
269 self.services.add(transient_factory(move |sp| {
270 let config: Ref<dyn Configure<T>> = Ref::new($struct_name {
271 name: name.clone(),
272 action: action.clone(),
273 $f1: sp.get_required::<$d1>(),
274 $f2: sp.get_required::<$d2>(),
275 $f3: sp.get_required::<$d3>(),
276 $f4: sp.get_required::<$d4>(),
277 _type: PhantomData,
278 });
279 config
280 }));
281
282 self
283 }
284
285 pub fn $post_method<F, $d1, $d2, $d3, $d4>(self, setup: F) -> Self
291 where
292 F: Fn(&mut T, Svc<$d1>, Svc<$d2>, Svc<$d3>, Svc<$d4>) + $($bounds)+,
293 $d1: $($bounds)+,
294 $d2: $($bounds)+,
295 $d3: $($bounds)+,
296 $d4: $($bounds)+,
297 {
298 let action = Ref::new(setup);
299 let name = self.name.clone();
300
301 self.services.add(transient_factory(move |sp| {
302 let config: Ref<dyn PostConfigure<T>> = Ref::new($struct_name {
303 name: name.clone(),
304 action: action.clone(),
305 $f1: sp.get_required::<$d1>(),
306 $f2: sp.get_required::<$d2>(),
307 $f3: sp.get_required::<$d3>(),
308 $f4: sp.get_required::<$d4>(),
309 _type: PhantomData,
310 });
311 config
312 }));
313
314 self
315 }
316 };
317 (($($bounds:tt)+), $method:ident, $post_method:ident, $struct_name:ident, ($d1:ident, $f1:ident), ($d2:ident, $f2:ident), ($d3:ident, $f3:ident), ($d4:ident, $f4:ident), ($d5:ident, $f5:ident)) => {
318 pub fn $method<F, $d1, $d2, $d3, $d4, $d5>(self, setup: F) -> Self
324 where
325 F: Fn(&mut T, Svc<$d1>, Svc<$d2>, Svc<$d3>, Svc<$d4>, Svc<$d5>) + $($bounds)+,
326 $d1: $($bounds)+,
327 $d2: $($bounds)+,
328 $d3: $($bounds)+,
329 $d4: $($bounds)+,
330 $d5: $($bounds)+,
331 {
332 let action = Ref::new(setup);
333 let name = self.name.clone();
334
335 self.services.add(transient_factory(move |sp| {
336 let config: Ref<dyn Configure<T>> = Ref::new($struct_name {
337 name: name.clone(),
338 action: action.clone(),
339 $f1: sp.get_required::<$d1>(),
340 $f2: sp.get_required::<$d2>(),
341 $f3: sp.get_required::<$d3>(),
342 $f4: sp.get_required::<$d4>(),
343 $f5: sp.get_required::<$d5>(),
344 _type: PhantomData,
345 });
346 config
347 }));
348
349 self
350 }
351
352 pub fn $post_method<F, $d1, $d2, $d3, $d4, $d5>(self, setup: F) -> Self
358 where
359 F: Fn(&mut T, Svc<$d1>, Svc<$d2>, Svc<$d3>, Svc<$d4>, Svc<$d5>) + $($bounds)+,
360 $d1: $($bounds)+,
361 $d2: $($bounds)+,
362 $d3: $($bounds)+,
363 $d4: $($bounds)+,
364 $d5: $($bounds)+,
365 {
366 let action = Ref::new(setup);
367 let name = self.name.clone();
368
369 self.services.add(transient_factory(move |sp| {
370 let config: Ref<dyn PostConfigure<T>> = Ref::new($struct_name {
371 name: name.clone(),
372 action: action.clone(),
373 $f1: sp.get_required::<$d1>(),
374 $f2: sp.get_required::<$d2>(),
375 $f3: sp.get_required::<$d3>(),
376 $f4: sp.get_required::<$d4>(),
377 $f5: sp.get_required::<$d5>(),
378 _type: PhantomData,
379 });
380 config
381 }));
382
383 self
384 }
385 };
386}
387
388macro_rules! configure_methods {
389 (($($bounds:tt)+)) => {
390 impl<'a, T: $($bounds)+> Builder<'a, T> {
391 pub fn configure<F>(self, setup: F) -> Self
397 where
398 F: Fn(&mut T) + $($bounds)+,
399 {
400 let configure = _Configure {
401 name: self.name.clone(),
402 action: setup,
403 _type: PhantomData::<T>,
404 };
405 let action: Ref<dyn Configure<T>> = Ref::new(configure);
406 let descriptor = singleton_factory(move |_| action.clone());
407 self.services.add(descriptor);
408 self
409 }
410
411 pub fn post_configure<F>(self, setup: F) -> Self
417 where
418 F: Fn(&mut T) + $($bounds)+,
419 {
420 let configure = _Configure {
421 name: self.name.clone(),
422 action: setup,
423 _type: PhantomData,
424 };
425 let action: Ref<dyn PostConfigure<T>> = Ref::new(configure);
426 let descriptor = singleton_factory(move |_| action.clone());
427 self.services.add(descriptor);
428 self
429 }
430
431 configure_builder_method!(($($bounds)+), configure1, post_configure1, _Configure1, (D, dependency));
432 configure_builder_method!(($($bounds)+), configure2, post_configure2, _Configure2, (D1, dependency1), (D2, dependency2));
433 configure_builder_method!(($($bounds)+), configure3, post_configure3, _Configure3, (D1, dependency1), (D2, dependency2), (D3, dependency3));
434 configure_builder_method!(($($bounds)+), configure4, post_configure4, _Configure4, (D1, dependency1), (D2, dependency2), (D3, dependency3), (D4, dependency4));
435 configure_builder_method!(($($bounds)+), configure5, post_configure5, _Configure5, (D1, dependency1), (D2, dependency2), (D3, dependency3), (D4, dependency4), (D5, dependency5));
436 }
437 };
438}
439
440cfg_if! {
441 if #[cfg(feature = "async")] {
442 configure_impl!((Send + Sync + 'static), _Configure, []);
443 configure_impl!((Send + Sync + 'static), _Configure1, [(TDep1, dependency)]);
444 configure_impl!((Send + Sync + 'static), _Configure2, [(TDep1, dependency1), (TDep2, dependency2)]);
445 configure_impl!((Send + Sync + 'static), _Configure3, [(TDep1, dependency1), (TDep2, dependency2), (TDep3, dependency3)]);
446 configure_impl!((Send + Sync + 'static), _Configure4, [(TDep1, dependency1), (TDep2, dependency2), (TDep3, dependency3), (TDep4, dependency4)]);
447 configure_impl!((Send + Sync + 'static), _Configure5, [(TDep1, dependency1), (TDep2, dependency2), (TDep3, dependency3), (TDep4, dependency4), (TDep5, dependency5)]);
448 configure_methods!((Send + Sync + 'static));
449 } else {
450 configure_impl!(('static), _Configure, []);
451 configure_impl!(('static), _Configure1, [(TDep1, dependency)]);
452 configure_impl!(('static), _Configure2, [(TDep1, dependency1), (TDep2, dependency2)]);
453 configure_impl!(('static), _Configure3, [(TDep1, dependency1), (TDep2, dependency2), (TDep3, dependency3)]);
454 configure_impl!(('static), _Configure4, [(TDep1, dependency1), (TDep2, dependency2), (TDep3, dependency3), (TDep4, dependency4)]);
455 configure_impl!(('static), _Configure5, [(TDep1, dependency1), (TDep2, dependency2), (TDep3, dependency3), (TDep4, dependency4), (TDep5, dependency5)]);
456 configure_methods!(('static));
457 }
458}