Skip to main content

options/prelude/builder/
configure.rs

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    // base case: zero dependencies
9    (($($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    // n-dependency case
41    (($($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
79// generates builder methods for configure/post_configure with n-dependencies
80macro_rules! configure_builder_method {
81    (($($bounds:tt)+), $method:ident, $post_method:ident, $struct_name:ident, ($d1:ident, $f1:ident)) => {
82        /// Registers an action used to configure a particular type of options.
83        ///
84        /// # Arguments
85        ///
86        /// * `setup` - The configuration action
87        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        /// Registers an action used to post-configure a particular type of options.
109        ///
110        /// # Arguments
111        ///
112        /// * `setup` - The configuration action
113        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        /// Registers an action used to configure a particular type of options.
136        ///
137        /// # Arguments
138        ///
139        /// * `setup` - The configuration action
140        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        /// Registers an action used to post-configure a particular type of options.
164        ///
165        /// # Arguments
166        ///
167        /// * `setup` - The configuration action
168        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        /// Registers an action used to configure a particular type of options.
193        ///
194        /// # Arguments
195        ///
196        /// * `setup` - The configuration action
197        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        /// Registers an action used to post-configure a particular type of options.
223        ///
224        /// # Arguments
225        ///
226        /// * `setup` - The configuration action
227        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        /// Registers an action used to configure a particular type of options.
254        ///
255        /// # Arguments
256        ///
257        /// * `setup` - The configuration action
258        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        /// Registers an action used to post-configure a particular type of options.
286        ///
287        /// # Arguments
288        ///
289        /// * `setup` - The configuration action
290        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        /// Registers an action used to configure a particular type of options.
319        ///
320        /// # Arguments
321        ///
322        /// * `setup` - The configuration action
323        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        /// Registers an action used to post-configure a particular type of options.
353        ///
354        /// # Arguments
355        ///
356        /// * `setup` - The configuration action
357        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            /// Registers an action used to configure a particular type of options.
392            ///
393            /// # Arguments
394            ///
395            /// * `setup` - The configuration action
396            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            /// Registers an action used to post-configure a particular type of options.
412            ///
413            /// # Arguments
414            ///
415            /// * `setup` - The configuration action
416            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}