1 /**
2 Provides annotation based configuration and registration for components.
3 
4 License:
5 	Boost Software License - Version 1.0 - August 17th, 2003
6 
7 	Permission is hereby granted, free of charge, to any person or organization
8 	obtaining a copy of the software and accompanying documentation covered by
9 	this license (the "Software") to use, reproduce, display, distribute,
10 	execute, and transmit the Software, and to prepare derivative works of the
11 	Software, and to permit third-parties to whom the Software is furnished to
12 	do so, all subject to the following:
13 
14 	The copyright notices in the Software and this entire statement, including
15 	the above license grant, this restriction and the following disclaimer,
16 	must be included in all copies of the Software, in whole or in part, and
17 	all derivative works of the Software, unless such copies or derivative
18 	works are solely in the form of machine-executable object code generated by
19 	a source language processor.
20 
21 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
24 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
25 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
26 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
27 	DEALINGS IN THE SOFTWARE.
28 
29 Authors:
30 	aermicioi
31 **/
32 module aermicioi.aedi.configurer.annotation.component_scan;
33 
34 import aermicioi.aedi.configurer.annotation.annotation;
35 import aermicioi.aedi.storage.locator;
36 import aermicioi.aedi.storage.storage;
37 import aermicioi.aedi.storage.alias_aware : AliasAware;
38 import aermicioi.aedi.storage.wrapper;
39 import aermicioi.aedi.container.container;
40 import aermicioi.aedi.factory.factory;
41 import aermicioi.aedi.factory.reference;
42 import aermicioi.aedi.factory.generic_factory;
43 import aermicioi.aedi.factory.proxy_factory;
44 import aermicioi.aedi.exception;
45 import aermicioi.aedi.util.traits;
46 import aermicioi.aedi.factory.wrapping_factory : WrappingFactory;
47 
48 import std.traits;
49 import std.meta;
50 import std.conv : to;
51 import std.algorithm;
52 import std.experimental.logger;
53 
54 /**
55 Check if a type T is a factory policy.
56 
57 Check if a type T is a factory policy.
58 A factory policy is a policy that based on type X, can
59 create a factory for type X.
60 **/
61 enum bool isFactoryPolicy(T, X = Object) = is(T == struct) && is(typeof(&T.createFactory!X) : Z function(Locator!()), Z : Factory!X);
62 
63 /**
64 Check if a type T is a configurator policy.
65 
66 Check if a type T is a configurator policy.
67 A configurator policy is a policy that given a type
68 X can create InstanceFactory, InstanceDestructor, or PropertyConfigurer
69 instances and add them to a factory that implements GenericFactory!X interface, as well
70 as modify other properties exposed by GenericFactory!X interface.
71 **/
72 enum bool isConfiguratorPolicy(T, X : GenericFactory!Z = GenericFactory!Object, Z) =
73     is(T == struct) &&
74     is(typeof(&T.configure!(X)) : void function(M, Locator!()), M : X);
75 
76 /**
77 Create a GenericFactory!T if T is annotated with @component annotation.
78 **/
79 @safe struct GenericFactoryPolicy {
80     /**
81     Create a GenericFactory!T if T is annotated with @component annotation.
82 
83     Params:
84         locator = locator used by factory to fetch it's dependencies
85 
86     Returns:
87         GenericFactory!T
88     **/
89     static GenericFactory!T createFactory(T)(Locator!() locator) {
90         GenericFactory!T factory;
91 
92         alias Components = allUDAs!T;
93         static foreach (index; 0 .. Components.length) {
94             static if (isComponentAnnotation!(Components[index])) {
95                 debug(annotationScanDebug) trace(typeid(T), " is marked with @component annotation, creating a component factory for it.");
96                 factory = new GenericFactoryImpl!T(locator);
97             }
98         }
99 
100         return factory;
101     }
102 }
103 
104 /**
105 A factory policy that uses annotations implementing factory policy interface on component to instantiate the component.
106 **/
107 @safe struct GenericFactoryAnnotationPolicy {
108 
109     /**
110     Create a component factory for T using annotations on it that implement factory policy interface.
111 
112     Params:
113         locator = locator of components used by component factory
114 
115     Returns:
116         A component factory
117     **/
118     static GenericFactory!T createFactory(T)(Locator!() locator) {
119 
120         GenericFactory!T factory;
121 
122         alias FactoryPolicies = allUDAs!T;
123 
124         static foreach (index; 0 .. FactoryPolicies.length) {
125             static if (isFactoryPolicy!(toType!(FactoryPolicies[index]), T)) {
126                 factory = FactoryPolicies[index].createFactory!T(locator);
127             }
128         }
129 
130         return factory;
131     }
132 }
133 
134 /**
135 A factory policy that applies in order a set of factory policies to create component factory.
136 **/
137 @safe struct FallbackFactoryPolicy(FactoryPolicies...)
138     if (allSatisfy!(isFactoryPolicy, FactoryPolicies)) {
139 
140     /**
141     Create component factory using one of supplied factory policies
142 
143     Params:
144         locator = locator of components used by component factory
145 
146     Returns:
147         A component factory, from the first factory policy that returned an instance
148     **/
149     static GenericFactory!T createFactory(T)(Locator!() locator) {
150 
151         static foreach (FactoryPolicy; FactoryPolicies) {{
152             GenericFactory!T factory = FactoryPolicy.createFactory!T(locator);
153 
154             if (factory !is null) {
155                 return factory;
156             }
157         }}
158 
159         return null;
160     }
161 }
162 
163 /**
164 Chain a set of configurator policies.
165 **/
166 @safe struct ChainedConfiguratorPolicy(ConfiguratorPolicies...)
167     if (allSatisfy!(isConfiguratorPolicy, ConfiguratorPolicies)) {
168 
169     /**
170     Run ConfiguratorPolicies on instantiator in sequential manner
171 
172     Params:
173         instantiator = factory which is configured by ConfiguratorPolicies
174         locator = locator used by factory
175 
176     **/
177     static void configure(T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
178 
179         foreach (policy; ConfiguratorPolicies) {
180             policy.configure(instantiator, locator);
181         }
182     }
183 }
184 
185 /**
186 Set allocator used by factory to instantiate component T.
187 **/
188 @safe struct AllocatorConfiguratorPolicy {
189 
190     /**
191     Set allocator from @allocator annotation into GenericFactory!Z.
192 
193     Params:
194         instantiator = factory which is set allocator from @allocator annotation
195         locator = locator used by factory
196     **/
197     static void configure(T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
198 
199         alias Allocators = allUDAs!Z;
200         static foreach (index; 0 .. Allocators.length) {
201             static if (isAllocatorAnnotation!(Allocators[index])) {
202                 debug(annotationScanDebug) trace(typeid(Z), " is marked with @allocator annotation, supplying component factory with custom allocator ", Allocators[index].allocator);
203                 instantiator.allocator = Allocators[index].iallocator;
204             }
205         }
206     }
207 }
208 
209 /**
210 Set callback instance factory from @callbac annotation into GenericFactory!Z
211 **/
212 @safe struct CallbackFactoryConfiguratorPolicy {
213     /**
214     Set callback instance factory from @callback annotation into GenericFactory!Z.
215 
216     Params:
217         instantiator = factory which is set callback instance factory from @callback annotation
218         locator = locator used by factory
219     **/
220     static void configure(T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
221         alias CallbackFactories = allUDAs!Z;
222 
223         static foreach (index; 0 .. CallbackFactories.length) {
224             static if (isCallbackFactoryAnnotation!(CallbackFactories[index])) {
225                 debug(annotationScanDebug) trace(
226                     typeid(Z),
227                     " is annotated with @callback annotation, supplying component factory with construction callable of ",
228                     typeid(CallbackFactories[index].dg),
229                     " and provided args ",
230                     CallbackFactories[index].args
231                 );
232                 instantiator.setInstanceFactory(callbackFactory(CallbackFactories[index].dg, CallbackFactories[index].args));
233             }
234         }
235     }
236 }
237 
238 /**
239 Set value factory that takes component from @value annotation and provides it as a new component.
240 **/
241 @safe struct ValueFactoryConfiguratorPolicy {
242 
243     /**
244     Set value factory that takes component from @value annotation and provides it as a new component.
245 
246     Params:
247         instantiator = factory which is set value instance factory from @value annotation
248         locator = locator used by factory
249     **/
250     static void configure(T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
251         alias ValueAnnotations = allUDAs!Z;
252         static foreach (index; 0 .. ValueAnnotations.length) {
253             static if (isValueAnnotation!(ValueAnnotations[index])) {
254 
255                 debug(annotationScanDebug) trace(typeid(Z), " is annotated with @value annotation, using ", ValueAnnotations[index].value, " as prebuilt component");
256                 instantiator.setInstanceFactory(new ValueInstanceFactory!Z(ValueAnnotations[index].value));
257             }
258         }
259     }
260 }
261 
262 /**
263 A policy that uses annotations that implement isConfigurerPolicy interface to configure the component factory
264 **/
265 @safe struct GenericConfigurerConfiguratorPolicy {
266     /**
267     Scans for annotations implementing isConfigurerPolicy interface and uses them to configure component factory.
268 
269     Params:
270         instantiator = factory upon which isConfigurerPolicy annotations are applied
271         locator = locator used by factory
272     **/
273     static void configure(T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
274         alias GenericConfigurerConfigurators = allUDAs!Z;
275         static foreach (index; 0 .. GenericConfigurerConfigurators.length) {
276             static if (isConfiguratorPolicy!(toType!(GenericConfigurerConfigurators[index]), T)) {
277 
278                 debug(annotationScanDebug) trace(
279                     typeid(Z),
280                     " is annotated with configuration policy ",
281                     typeid(GenericConfigurerConfigurators[index]),
282                     " invoking configure method on it using ",
283                     instantiator,
284                     " and ",
285                     locator
286                 );
287                 GenericConfigurerConfigurators[index].configure!(T)(instantiator, locator);
288             }
289         }
290     }
291 }
292 
293 /**
294 A policy that configures factory to use callback to destroy created components.
295 **/
296 @safe struct CallbackDestructorConfigurerPolicy {
297     /**
298     Configure instantiator to use callback for destruction of components
299 
300     Params:
301         instantiator = component factory
302         locator = container for component's dependencies
303         Z = type of component created
304     **/
305     static void configure(T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
306         auto CallbackDestructors = allUDAs!Z;
307         foreach (index; 0 .. CallbackDestructors.length) {
308             static if (isCallbackDestructor!(CallbackDestructors[index], T)) {
309 
310                 debug(annotationsScanDebug) trace(
311                     typeid(Z), " is annotated with @callbackDestructor callable of ", CallbackDestructors[index].dg, " with arguments of ", CallbackDestructors[index].args
312                 );
313                 instantiator.setInstanceDestructor(callbackDestructor(CallbackDestructors[index].dg, CallbackDestructors[index].args));
314             }
315         }
316     }
317 }
318 
319 /**
320 A dummy structure that is providing a simple field for isFieldConfiguratorPolicy interface for testing purposes of configurator templates.
321 **/
322 struct ConfiguredFieldTester {
323 
324     /**
325     Dummy field
326     **/
327     int field;
328 }
329 
330 /**
331 A dummy structure that is providing a simple method for isMethodConfiguratorPolicy interface for testing purposes of configurator templates.
332 **/
333 struct ConfiguredMethodTester {
334 
335     /**
336     Dummy method
337     **/
338     void method(int x) {}
339 }
340 
341 /**
342 Check if T is a field configurator policy that operates upon fields of a component.
343 
344 Params:
345     T = the type that is tested for field configurator policy interface
346     member = member field of constructed component by GenericFactory!Z
347     X = a factory for a component, on which policy can operate
348 Returns:
349     true if it is compliant, false otherwise
350 **/
351 enum bool isFieldConfiguratorPolicy(T, string member = "field", X : GenericFactory!Z = GenericFactory!ConfiguredFieldTester, Z) =
352     is(T == struct) &&
353     is(typeof(&T.configureField!(member, X)) : void function(X, Locator!()));
354 
355 /**
356 Check if T is a field configurator policy that operates upon methods of a component.
357 
358 Params:
359     T = the type that is tested for field configurator policy interface
360     member = member field of constructed component by GenericFactory!Z
361     X = a factory for a component, on which policy can operate
362 
363 Returns:
364     true if it is compliant, false otherwise
365 **/
366 enum bool isMethodConfiguratorPolicy(T, string member = "method", X : GenericFactory!Z = GenericFactory!ConfiguredMethodTester, Z) =
367     is(T == struct) &&
368     is(typeof(&T.configureMethod!(member, X)) : void function(X, Locator!()));
369 
370 /**
371 Configurator policy that applies method configurator policies on all public methods of a component
372 **/
373 @safe struct MethodScanningConfiguratorPolicy(MethodConfiguratorPolicies...)
374     if (allSatisfy!(isMethodConfiguratorPolicy, MethodConfiguratorPolicies)) {
375 
376     /**
377     Apply a set of method configurator policies on all public methods of component Z
378 
379     Params:
380         Z = component which will have it's methods scanned, including overloads.
381         instantiator = Z component factory
382         locator = locator used by method configurator policies
383     **/
384     static void configure(T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
385         foreach (member; __traits(allMembers, Z)) {
386             static if ((getProtection!(Z, member) == "public") && isSomeFunction!(__traits(getMember, Z, member))) {
387                 foreach (methodConfigurer; MethodConfiguratorPolicies) {
388                     methodConfigurer.configureMethod!member(instantiator, locator);
389                 }
390             }
391         }
392     }
393 }
394 
395 /**
396 Configurator policy that applies field configurator policies on all public methods of a component
397 **/
398 @safe struct FieldScanningConfiguratorPolicy(FieldConfiguratorPolicies...)
399     if (allSatisfy!(isFieldConfiguratorPolicy, FieldConfiguratorPolicies)) {
400 
401     /**
402     Apply a set of field configurator policies on all public fields of component Z
403 
404     Params:
405         Z = component which will have it's methods scanned, including overloads.
406         instantiator = Z component factory
407         locator = locator used by method configurator policies
408     **/
409     static void configure(T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
410         foreach (member; __traits(allMembers, Z)) {
411             static if ((getProtection!(Z, member) == "public") && isField!(Z, member)) {
412                 foreach (fieldConfigurer; FieldConfiguratorPolicies) {
413                     fieldConfigurer.configureField!member(instantiator, locator);
414                 }
415             }
416         }
417     }
418 }
419 
420 /**
421 Method configurator policy that scans only constructors for @constructor annotation, for using them to instantiate component Z
422 **/
423 @safe struct ConstructorMethodConfiguratorPolicy {
424 
425     /**
426     Checks if scanned method is a constructor and has @constructor annotation, and sets it to be used to construct component if so.
427 
428     Params:
429         Z = component type
430         member = member that should be scanned, only constructors are taken into account
431         instantiator = Z component factory, which policy will set constructor to be used to construct component if possible
432         locator = locator used to supply dependencies into constructor of component
433     **/
434     static void configureMethod(string member, T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
435 
436         static if (member == "__ctor") {
437             static foreach (overload; __traits(getOverloads, Z, member)) {{
438 
439 
440                 alias Configurers = allUDAs!overload;
441 
442                 static foreach (index; 0 .. Configurers.length) {{
443                     static if (isConstructorAnnotation!(Configurers[index])) {
444 
445                         debug(annotationScanDebug) trace(
446                             typeid(Z), " constructor", typeid(Parameters!overload),
447                             " is annotated with @constructor annotation, using it as means to construct component using supplied arguments of ", Configurers[index].args
448                         );
449                         auto tuple = Configurers[index].args;
450                         instantiator.setInstanceFactory(
451                             constructorBasedFactory!Z(tuple)
452                         );
453                     }
454                 }}
455             }}
456         }
457     }
458 }
459 
460 /**
461 Method policy that scans constructors for @autowired annotation to use them to construct component with dependencies identified by qualifier, name or their type.
462 **/
463 @safe struct AutowiredConstructorMethodConfiguratorPolicy {
464 
465     /**
466     Configures instantiator to use @autowired constructor method, to construct the component.
467 
468     Params:
469         Z = component type
470         member = method that is scanned. Only constructors are taken into account
471         instantiator = component constructor
472         locator = locator for component dependencies
473     **/
474     static void configureMethod(string member, T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
475 
476         static if (member == "__ctor") {
477             foreach (overload; __traits(getOverloads, Z, member)) {{
478 
479                 alias Configurers = allUDAs!overload;
480 
481                 static foreach (index; 0 .. Configurers.length) {
482                     static if (isAutowiredAnnotation!(Configurers[index])) {
483                         auto references = makeFunctionParameterReferences!overload.expand;
484                         debug(annotationScanDebug) trace(
485                             typeid(Z), " constructor", typeid(Parameters!(overload)),
486                             " is annotated with @autowired annotation, constructing component using this constructor with arguments of ", references
487                         );
488 
489                         instantiator.setInstanceFactory(
490                             constructorBasedFactory!Z(references)
491                         );
492                     }
493                 }
494             }}
495         }
496     }
497 }
498 
499 /**
500 Field configurator policy that will set a field annotated @setter annotation to value contained in it.
501 **/
502 @safe struct SetterFieldConfiguratorPolicy {
503 
504     /**
505     Configures instantiator to inject into field a predefined value or a dependency from @setter annotation
506 
507     Params:
508         Z = component type
509         member = field member of component
510         instantiator = component factory
511         locator = locator for component dependencies
512     **/
513     static void configureField(string member, T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
514 
515         alias Configurers = allUDAs!(__traits(getMember, Z, member));
516 
517         static foreach (index; 0 .. Configurers.length) {{
518             static if (isSetterAnnotation!(Configurers[index])) {
519 
520                 debug(annotationScanDebug) trace(
521                     typeid(Z), ".", member,
522                     " field is marked with @setter annotation. Using it to confiugre component with provided arguments of ", Configurers[index].args
523                 );
524 
525                 auto tuple = Configurers[index].args;
526                 instantiator.addPropertyConfigurer(fieldConfigurer!(member, Z)(tuple));
527             }
528         }}
529     }
530 }
531 
532 /**
533 Field configurator policy that will set a field to value returned by a callback in @callback annotation
534 **/
535 @safe struct CallbackFieldConfiguratorPolicy {
536 
537     /**
538     Configure instantiator to inject return value of callback from @callback annotation into field
539 
540     Params:
541         member = field that will be injected
542         Z = component type
543         instantiator = component factory
544         locator = locator for component dependencies
545     **/
546     static void configureField(string member, T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
547 
548         alias Callbacks = allUDAs!(__traits(getMember, Z, member));
549 
550         static foreach (index; 0 .. Callbacks.length) {
551             static if (isCallbackConfigurerAnnotation!(toType!(Callbacks[index]))) {
552 
553                 debug(annotationScanDebug) trace(
554                     typeid(Z), ".", member, " field is annotated with @callback annotation, using callback",
555                     Callbacks[index].dg, " with ", Callbacks[index].args, " to inject field with data."
556                 );
557                 instantiator.addPropertyConfigurer(callbackConfigurer!Z(Callbacks[index].dg, Callbacks[index].args));
558             }
559         }
560     }
561 }
562 
563 /**
564 Field configurator policy that will try to inject a dependency that matches fields type for fields that are annotated with @autowired annotation
565 **/
566 @safe struct AutowiredFieldConfiguratorPolicy {
567 
568     /**
569     Configure instantiator to inject into field a component identified by field's type if field has @autowired annotation.
570 
571     Params:
572         member = field that will be injected
573         Z = component type
574         instantiator = component factory
575         locator = locator for component dependencies
576     **/
577     static void configureField(string member, T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
578         alias field = Alias!(__traits(getMember, Z, member));
579 
580         alias Callbacks = allUDAs!field;
581 
582         static foreach (index; 0 .. Callbacks.length) {{
583             static if (isAutowiredAnnotation!(Callbacks[index])) {
584 
585                 RuntimeReference reference;
586 
587                 mixin(transformToReference("reference", "field"));
588 
589                 debug(annotationScanDebug) trace(typeid(Z), ".", member, " field is annotated with @autowired annotation, injecting it with ", reference);
590 
591                 instantiator.addPropertyConfigurer(fieldConfigurer!(member, Z)(reference));
592             }
593         }}
594     }
595 }
596 
597 /**
598 Method configurator policy that will call a method with resolved arguments from @setter annotation.
599 **/
600 @safe struct SetterMethodConfiguratorPolicy {
601 
602     /**
603     Configure instantiator to call @setter annotated method with arguments from annotation
604 
605     Params:
606         Z = component type
607         member = method that would be called by factory
608         instantiator = component factory
609         locator = locator for component dependencies
610     **/
611     static void configureMethod(string member, T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
612 
613         static foreach (overload; __traits(getOverloads, Z, member)) {{
614 
615             alias Configurers = allUDAs!overload;
616 
617             static foreach (index; 0 .. Configurers.length) {{
618                 static if (isSetterAnnotation!(Configurers[index])) {
619                     debug(annotationScanDebug) trace(typeid(Z), ".", member, " method is marked with @setter annotation, injecting it with ", Configurers[index].args);
620                     auto tuple = Configurers[index].args;
621                     instantiator.addPropertyConfigurer(methodConfigurer!(member, Z)(tuple));
622                 }
623             }}
624         }}
625     }
626 }
627 
628 /**
629 Method configurator policy that will call callback from @callback annotated methods.
630 **/
631 @safe struct CallbackMethodConfiguratorPolicy {
632 
633     /**
634     Configre instantiator to call callback from @callback annotation with arguments that are stored in annotation
635 
636     Params:
637         Z = component type
638         member = method which is annotated with @callback. It is supposed that callback will use it somehow in logic.
639         instantiator = component factory
640         locator = locator for component dependencies
641     **/
642     static void configureMethod(string member, T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
643 
644         static foreach (overload; __traits(getOverloads, Z, member)) {{
645 
646             alias Configurers = allUDAs!overload;
647 
648             static foreach (index; 0 .. Configurers.length) {
649                 static if (isCallbackConfigurerAnnotation!(toType!(Configurers[index]))) {
650 
651                     debug(annotationScanDebug) trace(typeid(Z), ".", member, " method is marked with @callback annotation, using callback", Configurers[index].dg, " with ", Configurers[index].args, " to configure component.");
652                     instantiator.addPropertyConfigurer(callbackConfigurer!Z(Configurers[index].dg, Configurers[index].args));
653                 }
654             }
655         }}
656     }
657 }
658 
659 /**
660 Method configurator policy that will call method annotated with @autowire with arguments extracted from locator identified by qualifier, name or their type.
661 **/
662 @safe struct AutowiredMethodConfiguratorPolicy {
663 
664     /**
665     Configure instantiator to call a method annotated with @autowired with arguments extracted from locator
666 
667     Params:
668         Z = component type
669         member = method that is annotated with @autowired annotation
670         instantiator = component factory
671         locator = locator for component dependencies
672     **/
673     static void configureMethod(string member, T : GenericFactory!Z, Z)(T instantiator, Locator!() locator) {
674         static if (member != "__ctor") {
675             static foreach (overload; __traits(getOverloads, Z, member)) {{
676 
677                 alias Configurers = allUDAs!overload;
678 
679                 static foreach (index; 0 .. Configurers.length) {
680                     static if (isAutowiredAnnotation!(Configurers[index])) {
681                         auto references = makeFunctionParameterReferences!overload.expand;
682 
683                         debug(annotationScanDebug) trace(typeid(Z), ".", member, " method is marked with @autowired annotation, injecting it with ", references);
684 
685                         instantiator.addPropertyConfigurer(methodConfigurer!(member, Z)(references));
686                     }
687                 }
688             }}
689         }
690     }
691 }
692 
693 /**
694 Check if a policy implements transformer interface.
695 
696 A transformer is a policy that takes a type, and optionally a member of it, and transform it
697 into a component factory using annotations from component, or member.
698 
699 Params:
700     T = type to be tested for interface implementation
701     X = a test object that is used to test templated methods of policy
702 Returns:
703     true if it implements Transformer interface, false otherwise
704 **/
705 enum bool isTransformer(T, X = Object) = is(T == struct) && is(typeof(&T.transform!X) : void function (Locator!(), Storage!(ObjectFactory, string)));
706 
707 /**
708 A transformer that creates out of a type a GenericFactory for passed type
709 **/
710 @safe struct TypeTransformer(FactoryPolicy, ConfigurerPolicy)
711     if (isFactoryPolicy!FactoryPolicy && isConfiguratorPolicy!ConfigurerPolicy) {
712 
713     /**
714     Transform type T into a GenericFactory!T
715 
716     Params:
717         T = type which is transformed into it's factory
718         locator = locator for T's dependencies
719     Returns:
720         instance of GenericFactory!T, or null if T is not transformable into a factory
721     **/
722     static auto transform(T)(Locator!() locator)
723         if (is(T)) {
724         auto instantiator = FactoryPolicy.createFactory!T(locator);
725 
726         if (instantiator is null) {
727             return instantiator;
728         }
729 
730         ConfigurerPolicy.configure(instantiator, locator);
731 
732         return instantiator;
733     }
734 }
735 
736 /**
737 Transformer that wraps results of another transformer in WrappingFactory
738 **/
739 @safe struct ObjectFactoryTransformer(TransformerPolicy) {
740 
741     /**
742     Wrap up results of another transformer into WrappingFactory
743 
744     Params:
745         T = type of component that is transformed
746 
747     Returns:
748         null if T is not transformable, or instance of WrappingFactory that wraps result of TransformerPolicy
749     **/
750     static auto transform(T)(Locator!() locator)
751         if (is(T)) {
752 
753         auto instantiator = TransformerPolicy.transform!T(locator);
754 
755         if (instantiator is null) {
756             return cast(WrappingFactory!(typeof(instantiator))) null;
757         }
758 
759         return new WrappingFactory!(typeof(instantiator))(instantiator);
760     }
761 }
762 
763 /**
764 Check if T implements ContainerAdder interface.
765 
766 A ContainerAdder is component that is responsible to scan
767 a symbol for it's members, transform them using passed Transformers,
768 and add them to storage.
769 
770 Params:
771     T = component that is tested for ContainerAdder interface.
772     X = a dummy symbol used to test templated methods of component
773 
774 Note:
775     Due to possibility to store any kind of symbol in X (not only types),
776     the use of this checker is limited in use for generic testing.
777     Ex. ContainerAdder for modules and types are technically different interfaces
778     and will fail the checker when are tested both with same X argument
779     (module is not a type), though they are conceptually the same.
780 Returns:
781     true if it implements ContainerAdder interface, false otherwise
782 **/
783 enum bool isContainerAdder(T, alias X = Object) =
784     is(T == struct) &&
785     is(typeof(&T.scan!X) : V function (X, Y), X : Locator!(), Y : Storage!(Factory!Object, string), V);
786 
787 /**
788 Check if T implements component storing interface.
789 
790 The responsibility of component storing policy is to
791 store component's factory into appropiate storage,
792 by apropiate identity, using information about type T.
793 
794 Params:
795     T = type that is tested for interface compliance
796     X = component type against which T's templates are tested to comply to interface
797 Returns:
798     true if it implements the interface, false otherwise
799 **/
800 enum bool isComponentStoringPolicy(T, X = Object) =
801     is(T == struct) &&
802     is(
803         typeof(&T.store!X) : ComponentStoringResult function (F, Locator!(), S),
804         F : Factory!Z,
805         Z,
806         S : Storage!(Factory!Z, string)
807     );
808 
809 /**
810 Check if T implements identity resolver interface.
811 
812 The responsibility of identity resolver policy is to
813 find an identity for component that is to be stored based
814 on information provided on passed type.
815 
816 Params:
817     T = type that is tested for interface compliance
818     X = component type against which T's templates are tested to comply to interface
819 Returns:
820     true if it implements the interface, false otherwise
821 **/
822 enum bool isIdentityResolverPolicy(T, X = Object) =
823     is(T == struct) &&
824     is(
825         typeof(&T.resolve!X) : string function (F),
826         F : Factory!Z,
827         Z
828     );
829 
830 /**
831 Check if T implements storage resolver interface.
832 
833 The responsibility of storage resolver policy is to
834 find a storage for component which will store component
835 based on information provided on passed type.
836 
837 Params:
838     T = type that is tested for interface compliance
839     X = component type against which T's templates are tested to comply to interface
840 Returns:
841     true if it implements the interface, false otherwise
842 **/
843 enum bool isStorageLocatorPolicy(T, X = Object) =
844     is(T == struct) &&
845     is(
846         typeof(&T.search!X) : Storage!(Factory!Z, string) function (F, Locator!(), S),
847         F : Factory!Z,
848         Z,
849         S : Storage!(Factory!Z, string)
850     );
851 
852 /**
853 Check if T implements identity aliasing interface.
854 
855 The responsibility of identity aliasing policy is to
856 find aliases of component's identity that should be registered
857 in component storage.
858 
859 Params:
860     T = type that is tested for interface compliance
861     X = component type against which T's templates are tested to comply to interface
862 Returns:
863     true if it implements the interface, false otherwise
864 **/
865 enum bool isAliasingPolicy(T, X = Object) =
866     is(T == struct) &&
867     is(
868         typeof(&T.link!X) : void function (string, AliasAware!string)
869     );
870 
871 /**
872 Result of storing a component into a storage.
873 **/
874 struct ComponentStoringResult {
875 
876     /**
877     Primary identity of stored component
878     **/
879     string identity;
880 
881     /**
882     Storage where it was stored.
883     **/
884     Storage!(ObjectFactory, string) storage;
885 }
886 
887 /**
888 A default implementation of component storing policy that looks for @qualifier and @contained annotations to store component factory.
889 **/
890 @safe struct ComponentStoringPolicy(IdentityResolverPolicy, StorageResolvingPolicy, AliasingPolicyImpl) {
891     /**
892     Store component factory into storage.
893 
894     Store component factory into storage. The storage where component is stored
895     on presence of @contained annotation on T, will be extracted from locator, otherwise
896     storage passed as argument is used. The identity of component by default is
897     it's type FQN, but is overriden by @qualifier annotation.
898 
899     Params:
900         factory = component factory to be stored
901         locator = locator that is used to fetch storage in case of @contained annotation
902         storage = storage were component is stored when no @contained annotation is provided
903     **/
904     static ComponentStoringResult store(alias T)(Factory!Object factory, Locator!() locator, Storage!(Factory!Object, string) storage) {
905 
906         string identity = IdentityResolverPolicy.resolve!T(factory);
907 
908         auto destinationStorage = StorageResolvingPolicy.search!T(factory, locator, storage);
909 
910         if ((identity !is null) && (destinationStorage !is null)) {
911             destinationStorage.set(factory, identity);
912 
913             AliasAware!string aliasingContainer = (() @trusted => cast(AliasAware!string) destinationStorage)();
914             if (aliasingContainer !is null) {
915                 AliasingPolicyImpl.link!T(identity, aliasingContainer);
916             }
917 
918             return ComponentStoringResult(identity, destinationStorage);
919         }
920 
921 
922         return ComponentStoringResult.init;
923     }
924 }
925 
926 /**
927 A implementation that will chain several storing policies, triggerring multiple registrations of same component.
928 **/
929 @safe struct ChainedComponentStoringPolicy(ComponentStoringPolicies...)
930     if (allSatisfy!(isComponentStoringPolicy, ComponentStoringPolicies)) {
931 
932     /**
933     Store component factory into multiple storages by using multiple policies.
934 
935     Params:
936         factory = component factory to be stored
937         locator = locator that is used to fetch storage in case of @contained annotation
938         storage = storage were component is stored when no @contained annotation is provided
939     **/
940     static ComponentStoringResult store(alias T)(Factory!Object factory, Locator!() locator, Storage!(Factory!Object, string) storage) {
941         ComponentStoringResult result;
942         foreach (ComponentStoringPolicy; ComponentStoringPolicies) {
943             result = ComponentStoringPolicy.store!T(factory, locator, storage);
944 
945             if (result !is ComponentStoringResult.init) {
946                 break;
947             }
948         }
949 
950         return result;
951     }
952 }
953 
954 /**
955 Default implementation of storage policy used by adders.
956 **/
957 alias ComponentStoringPolicyImpl = ComponentStoringPolicy!(
958     IdentityResolverPolicyImpl,
959     StorageLocatorPolicyImpl,
960     AliasingPolicyImpl
961 );
962 
963 /**
964 Qualifier implementation of aliasing policy.
965 **/
966 @safe struct QualifiedAnnotationAliasingPolicy {
967 
968     /**
969     Alias an identity in a aliasing container based on qualifier annotations on component.
970 
971     Params:
972         identity = main identity of component registered in aliased container.
973         aliasingContainer = container that is keeping aliasing information.
974     **/
975     static void link(alias T)(string identity, AliasAware!string aliasingContainer) {
976 
977         alias Qualifiers = allUDAs!T;
978         static foreach (index; 0 .. Qualifiers.length) {
979             static if (isQualifierAnnotation!(Qualifiers[index])) {
980                 if (identity != Qualifiers[index].id) {
981                     debug(annotationScanDebug) trace(
982                         fullyQualifiedName!T, " is marked with @qualifier annotation, aliasing identitity ",
983                         identity, " of component to ", Qualifiers[index].id
984                     );
985 
986                     aliasingContainer.link(identity, Qualifiers[index].id);
987                 }
988             }
989         }
990     }
991 }
992 
993 /**
994 By identifier implementation of aliasing policy.
995 **/
996 @safe struct IdentifierAliasingPolicy {
997 
998     /**
999     Alias an identity in a aliasing container based on it's identifier.
1000 
1001     Params:
1002         identity = main identity of component registered in aliased container.
1003         aliasingContainer = container that is keeping aliasing information.
1004     **/
1005     static void link(alias T)(string identity, AliasAware!string aliasingContainer) {
1006 
1007         static if (is(typeof(__traits(identifier, T)))) {
1008             static immutable identifier = __traits(identifier, T);
1009             if (identifier != identity) {
1010                 debug(annotationScanDebug) trace(
1011                     fullyQualifiedName!T, " has identifier of ", identifier, ", aliasing it to identitity of ", identity
1012                 );
1013 
1014                 aliasingContainer.link(identity, identifier[]);
1015             }
1016         }
1017     }
1018 }
1019 
1020 /**
1021 By type implementation of aliasing policy.
1022 **/
1023 @safe struct TypeAliasingPolicy {
1024 
1025     /**
1026     Alias an identity in a aliasing container based on type of component.
1027 
1028     Params:
1029         identity = main identity of component registered in aliased container.
1030         aliasingContainer = container that is keeping aliasing information.
1031     **/
1032     static void link(alias T)(string identity, AliasAware!string aliasingContainer) {
1033 
1034         static if (is(typeof({ auto test = typeid(T); }))) {
1035 
1036             if (typeid(T).toString != identity) {
1037                 debug(annotationScanDebug) trace(
1038                     typeid(T), " has identity ", identity, " which is not FQN of component, aliasing it to ", typeid(T), " of component using typeid"
1039                 );
1040                 aliasingContainer.link(identity, typeid(T).toString);
1041             }
1042 
1043             if ((typeid(T).toString != fullyQualifiedName!T) && (fullyQualifiedName!T != identity)) {
1044                 debug(annotationScanDebug) trace(
1045                     typeid(T), " has identity ", identity, " which is not FQN of component, aliasing it to ", typeid(T), " of component using fullyQualifiedName"
1046                 );
1047                 aliasingContainer.link(identity, fullyQualifiedName!T);
1048             }
1049         }
1050     }
1051 }
1052 
1053 /**
1054 Chaining implementation of aliasing policy, calling other passed policies.
1055 **/
1056 @safe struct ChainedAliasingPolicy(Policies...)
1057     if (allSatisfy!(isAliasingPolicy, Policies)) {
1058 
1059     /**
1060     Alias an identity in a aliasing container using aliasing policies passed to this policy.
1061 
1062     Params:
1063         identity = main identity of component registered in aliased container.
1064         aliasingContainer = container that is keeping aliasing information.
1065     **/
1066     static void link(alias T)(string identity, AliasAware!string aliasingContainer) {
1067         static foreach (Policy; Policies) {
1068             Policy.link!T(identity, aliasingContainer);
1069         }
1070     }
1071 }
1072 
1073 /**
1074 Default configuration of aliasing policy
1075 **/
1076 alias AliasingPolicyImpl = ChainedAliasingPolicy!(
1077     QualifiedAnnotationAliasingPolicy,
1078     IdentifierAliasingPolicy,
1079     TypeAliasingPolicy
1080 );
1081 
1082 /**
1083 A implementation storage locator policy that searches for storage of component based on @contained annotation
1084 **/
1085 @safe struct ContainedAnnotationStorageLocatorPolicy {
1086 
1087     /**
1088     Find a storge in locator based upon @contained annotation
1089 
1090     Params:
1091         factory = component factory to be stored
1092         locator = locator that is used to fetch storage in case of @contained annotation is present
1093         storage = default storage
1094     **/
1095     static Storage!(Factory!Object, string) search(alias T)(Factory!Object factory, Locator!() locator, Storage!(Factory!Object, string) storage) {
1096         string id;
1097 
1098         alias ContainedAnnotations = allUDAs!T;
1099         static foreach (index; 0 .. ContainedAnnotations.length) {
1100             static if (isContainedAnnotation!(ContainedAnnotations[index])) {
1101 
1102                 if (locator.has(ContainedAnnotations[index].id)) {
1103                     debug(annotationScanDebug) trace(
1104                         typeid(T), " is marked with custom @contained annotation, using storage identified by ",
1105                         ContainedAnnotations[index].id, " to store component factory"
1106                     );
1107                     id = ContainedAnnotations[index].id;
1108                 }
1109             }
1110         }
1111 
1112         if (id !is null) {
1113             return locator.locate!(Storage!(Factory!Object, string))(id);
1114         }
1115 
1116         return null;
1117     }
1118 }
1119 
1120 /**
1121 A implementation storage locator policy that will return default storage for component which is passed as argument to search.
1122 **/
1123 @safe struct DefaultStorageLocatorPolicy {
1124 
1125     /**
1126     Find a storge in locator based upon @contained annotation
1127 
1128     Params:
1129         factory = component factory to be stored
1130         locator = locator that is used to fetch storage in case of @contained annotation
1131         storage = default storage
1132     **/
1133     static Storage!(Factory!Object, string) search(alias T)(Factory!Object factory, Locator!() locator, Storage!(Factory!Object, string) storage) {
1134 
1135         return storage;
1136     }
1137 }
1138 
1139 /**
1140 A implementation storage locator policy that will apply other policies in chain until one provides a storage for storing data.
1141 **/
1142 @safe struct ChainedStorageLocatorPolicy(StorageLocatorPolicies...)
1143     if (allSatisfy!(isStorageLocatorPolicy, StorageLocatorPolicies)) {
1144 
1145     /**
1146     Get default storage for component.
1147 
1148     Params:
1149         factory = component factory to be stored
1150         locator = locator that is used to fetch storage in case of @contained annotation
1151         storage = default storage
1152     **/
1153     static Storage!(Factory!Object, string) search(alias T)(Factory!Object factory, Locator!() locator, Storage!(Factory!Object, string) storage) {
1154 
1155         static foreach (StorageLocatorPolicy; StorageLocatorPolicies) {{
1156             auto destination = StorageLocatorPolicy.search!T(factory, locator, storage);
1157 
1158             if (destination !is null) {
1159                 return destination;
1160             }
1161         }}
1162 
1163         return null;
1164     }
1165 }
1166 
1167 /**
1168 Default policy implementation for searching of storage for component
1169 **/
1170 alias StorageLocatorPolicyImpl = ChainedStorageLocatorPolicy!(
1171     ContainedAnnotationStorageLocatorPolicy,
1172     DefaultStorageLocatorPolicy
1173 );
1174 
1175 /**
1176 A policy for resolving identity of component by annotation.
1177 **/
1178 @safe struct QualifiedAnnotationIdentityResolverPolicy {
1179 
1180     /**
1181     Resolve identity of component by qualified annotations on it.
1182 
1183     The first qualified annotation is returned from list of annotations. If no annotations
1184     are on the component T, null is returned.
1185 
1186     Params:
1187         factory = component factory to be stored
1188 
1189     Returns:
1190         identity of component based on annotation or null.
1191     **/
1192     static string resolve(alias T)(Factory!Object factory) {
1193         string identity;
1194 
1195         alias Qualifiers = allUDAs!T;
1196         static foreach (index; 0 .. Qualifiers.length) {{
1197             static if (!is(typeof(found)) && isQualifierAnnotation!(Qualifiers[index])) {
1198                 debug(annotationScanDebug) trace(
1199                     fullyQualifiedName!T, " is marked with @qualifier annotation, using ", Qualifiers[index].id, " as main identity for component."
1200                 );
1201                 identity = Qualifiers[index].id;
1202                 enum found = true;
1203             }
1204         }}
1205 
1206         return identity;
1207     }
1208 }
1209 
1210 /**
1211 A policy for resolving identity of component by it's type.
1212 **/
1213 @safe struct TypeIdentityResolverPolicy {
1214 
1215     /**
1216     Resolve identity of component by FQN of it's type.
1217 
1218     Params:
1219         factory = component factory to be stored
1220 
1221     Returns:
1222         FQN of component type as it's identity.
1223     **/
1224     static string resolve(alias T)(Factory!Object factory) {
1225 
1226         debug(annotationScanDebug) trace(
1227             fullyQualifiedName!T, " has no custom identities, using it's type FQN as main identity."
1228         );
1229         return fullyQualifiedName!T;
1230     }
1231 }
1232 
1233 /**
1234 A policy for resolving identity of component by it's identifier.
1235 **/
1236 @safe struct IdentifierBasedIdentityResolverPolicy {
1237 
1238     /**
1239     Resolve identity of component by identifier attached to it.
1240 
1241     Params:
1242         factory = component factory to be stored
1243 
1244     Returns:
1245         identifier as identity of component or null.
1246     **/
1247     static string resolve(alias T)(Factory!Object factory) {
1248 
1249         static if (is(typeof(__traits(identifier, T)))) {
1250             static immutable string identifier = __traits(identifier, T);
1251             debug(annotationScanDebug) trace(
1252                 fullyQualifiedName!T, " has identifier ", identifier, " using it as main identity for component."
1253             );
1254 
1255             return identifier;
1256         } else {
1257 
1258             return null;
1259         }
1260     }
1261 }
1262 
1263 /**
1264 A policy for resolving identity of component by applying other components in chain.
1265 **/
1266 @safe struct ChainedIdentityResolverPolicy(IdentityResolverPolicies...)
1267     if (allSatisfy!(isIdentityResolverPolicy, IdentityResolverPolicies)) {
1268 
1269     /**
1270     Resolve identity of component by FQN of it's type.
1271 
1272     Params:
1273         factory = component factory to be stored
1274 
1275     Returns:
1276         FQN of component type as it's identity.
1277     **/
1278     static string resolve(alias T)(Factory!Object factory) {
1279 
1280         static foreach (IdentityResolverPolicy; IdentityResolverPolicies) {{
1281             string identity = IdentityResolverPolicy.resolve!T(factory);
1282 
1283             if (identity !is null) {
1284                 return identity;
1285             }
1286         }}
1287 
1288         return null;
1289     }
1290 }
1291 
1292 /**
1293 Default implementation of identity resolving policy
1294 **/
1295 alias IdentityResolverPolicyImpl = ChainedIdentityResolverPolicy!(
1296     QualifiedAnnotationIdentityResolverPolicy,
1297     TypeIdentityResolverPolicy
1298 );
1299 
1300 /**
1301 ContainerAdder that chains a set of ContainerAdders on a symbol.
1302 **/
1303 @safe struct ChainedContainerAdder(ContainerAdderPolicies...) {
1304     import aermicioi.aedi.util.traits : getMember;
1305 
1306     /**
1307     Check if at least one ContainerAdder supports passed symbol
1308 
1309     Params:
1310         T = symbol that at least one ContainerAdder, must know how to scan
1311     Returns:
1312         true if at least one ContainerAdder knows how to scan symbol, false otherwise
1313     **/
1314     enum bool isSupported(alias T) = anySatisfied!(T, staticMap!(ApplyRight!(getMember, "isSupported"), ContainerAdderPolicies));
1315 
1316     /**
1317     Apply all ContainerAdders that know how to scan T symbol
1318 
1319     Params:
1320         T = symbol to be scanned
1321         locator = locator of components, used by transformer that is applied on members of scanned T symbol
1322         storage = the storage that will store component factories from transformed members of T symbol
1323     **/
1324     static void scan(alias T)(Locator!() locator, Storage!(ObjectFactory, string) storage)
1325         if (isSupported!T) {
1326         foreach (ContainerAdderPolicy; ContainerAdderPolicies) {
1327             static if (ContainerAdderPolicy.isSupported!T) {
1328                 ContainerAdderPolicy.scan!T(locator, storage);
1329             }
1330         }
1331     }
1332 }
1333 
1334 /**
1335 Applies a transformer on passed symbol if it is a type.
1336 **/
1337 @safe struct TypeContainerAdder(TypeTransformerPolicy, ComponentStoringPolicy = ComponentStoringPolicyImpl)
1338     if (isComponentStoringPolicy!ComponentStoringPolicy) {
1339 
1340     /**
1341     Check if symbol T is a type definition.
1342 
1343     Params:
1344         T = symbol to be tested
1345     Returns:
1346         true if it is a type, false otherwise
1347     **/
1348     enum bool isSupported(alias T) = is(T);
1349 
1350     /**
1351     Transform T component into a factory using TypeTransformerPolicy
1352 
1353     Params:
1354         T = component type
1355         locator = component locator used by transformed component factory
1356         storage = storage wich will contain component factory transformed out of T
1357     **/
1358     static void scan(T)(Locator!() locator, Storage!(ObjectFactory, string) storage)
1359         if (isSupported!T) {
1360 
1361         auto transformed = TypeTransformerPolicy.transform!T(locator);
1362 
1363         if (transformed is null) {
1364             return;
1365         }
1366 
1367         ComponentStoringPolicy.store!T(transformed, locator, storage);
1368     }
1369 }
1370 
1371 /**
1372 ContainerAdder that scans a type for inner static types, to transform and store into a storage.
1373 **/
1374 @safe struct InnerTypeContainerAdder(ContainerAdderPolicy) {
1375 
1376     /**
1377     Check if T symbol is a type
1378 
1379     Params:
1380         T = symbol to be tested
1381 
1382     Returns:
1383         true if it is a type, false otherwise
1384     **/
1385     enum bool isSupported(alias T) = is(T);
1386 
1387     /**
1388     Scan type T for inner static types, to transform them and store in storage
1389 
1390     Params:
1391         T = type that will be scanned for inner static types
1392         locator = locator of components used by transformed component factories
1393         storage = storage which will contain transformed component factories
1394     **/
1395     static void scan(T)(Locator!() locator, Storage!(ObjectFactory, string) storage)
1396         if(isSupported!T) {
1397 
1398         foreach (member; __traits(allMembers, T)) {
1399             static if (isPublic!(T, member) && is(Alias!(__traits(getMember, T, member)))) {
1400 
1401                 ContainerAdderPolicy.scan!(getMember!(T, member))(locator, storage);
1402                 scan!(getMember!(T, member))(locator, storage);
1403             }
1404         }
1405     }
1406 }
1407 
1408 /**
1409 ContainerAdder that will scan a module for it's members, to transform into component factories and add them into a storage
1410 **/
1411 @safe struct ModuleContainerAdder(ContainerAdderPolicy) {
1412     import std.algorithm : startsWith;
1413     /**
1414     Check if T symbol is a module.
1415 
1416     Params:
1417         T = symbol to be tested
1418 
1419     Returns:
1420         true if it is a module, false otherwise
1421     **/
1422     enum bool isSupported(alias T) = T.stringof.startsWith("module");
1423 
1424     /**
1425     Scan module T, transform it's members into component factories, and store them into storage.
1426 
1427     Params:
1428         T = module that is scanned
1429         locator = locator of components used by transformed component factories
1430         storage = storage which will contain component factories
1431     **/
1432     static void scan(alias T)(Locator!() locator, Storage!(ObjectFactory, string) storage)
1433         if (isSupported!T) {
1434 
1435         foreach (member; __traits(allMembers, T)) {
1436             static if (isPublic!(T, member) && is(Alias!(__traits(getMember, T, member)))) {
1437                 ContainerAdderPolicy.scan!(getMember!(T, member))(locator, storage);
1438             }
1439         }
1440     }
1441 }
1442 
1443 /**
1444 ContainerAdder that will ignore specific packages.
1445 
1446 Params:
1447     pack = package that will be ignored.
1448     ContainerAdderPolicy = policy run on not ignored packages.
1449 **/
1450 @safe struct IgnoringContainerAdder(string pack, ContainerAdderPolicy) {
1451     import std.algorithm : startsWith, canFind;
1452     import std.traits : packageName;
1453     /**
1454     Check if T symbol is a module.
1455 
1456     Params:
1457         T = symbol to be tested
1458 
1459     Returns:
1460         true if it is a module, false otherwise
1461     **/
1462     enum bool isSupported(alias T) = (!moduleName!T.canFind(".") || !moduleName!T.startsWith(pack)) && ContainerAdderPolicy.isSupported!T;
1463 
1464     /**
1465     Scan T if it is not in ignored package.
1466 
1467     Params:
1468         T = module that is scanned
1469         locator = locator of components used by transformed component factories
1470         storage = storage which will contain component factories
1471     **/
1472     static void scan(alias T)(Locator!() locator, Storage!(ObjectFactory, string) storage)
1473         if (isSupported!T) {
1474         ContainerAdderPolicy.scan!T(locator, storage);
1475     }
1476 }
1477 
1478 /**
1479 ContainerAdder that will scan a type for it's methods, and use them to create component factories out of their return type
1480 **/
1481 @safe struct FactoryMethodContainerAdder(
1482     ByTypeComponentStoringPolicy = ComponentStoringPolicyImpl,
1483     ByMethodComponentStoringPolicy = ComponentStoringPolicy!(
1484         ChainedIdentityResolverPolicy!(
1485             QualifiedAnnotationIdentityResolverPolicy,
1486             IdentifierBasedIdentityResolverPolicy
1487         ),
1488         StorageLocatorPolicyImpl,
1489         AliasingPolicyImpl
1490     ),
1491     ByTypeAliasingPolicy = TypeAliasingPolicy
1492 ) if (isComponentStoringPolicy!ByTypeComponentStoringPolicy && isComponentStoringPolicy!ByMethodComponentStoringPolicy && isAliasingPolicy!ByTypeAliasingPolicy) {
1493     import std.algorithm : startsWith;
1494 
1495     /**
1496     Check if symbol T is a type or module
1497 
1498     Params:
1499         T = symbol to be tested
1500 
1501     Returns:
1502         true if it is a type, false otherwise
1503     **/
1504     enum bool isSupported(alias T) = isModule!T || isType!T;
1505 
1506     /**
1507     ditto
1508     **/
1509     enum bool isModule(alias T) = T.stringof.startsWith("module");
1510 
1511     /**
1512     ditto
1513     **/
1514     enum bool isType(alias T) = is(T);
1515 
1516     /**
1517     Scan T's methods, for methods annotated with @component annotation, transform them into component factories
1518     that will use them to create components of returned type.
1519 
1520     Params:
1521         T = type to be scanned
1522         locator = locator of components used by component factories
1523         storage = storage which will contain component factories
1524     **/
1525     static void scan(alias T)(Locator!() locator, Storage!(ObjectFactory, string) storage)
1526         if (isSupported!T) {
1527 
1528         static foreach (member; __traits(allMembers, T)) {{
1529             static if (isPublic!(T, member) && isSomeFunction!(__traits(getMember, T, member))) {
1530 
1531                 static foreach (overload; __traits(getOverloads, T, member)) {{
1532 
1533                     alias FactoryMethods = allUDAs!overload;
1534 
1535                     static foreach (index; 0 .. FactoryMethods.length) {{
1536                         static if (isComponentAnnotation!(FactoryMethods[index])) {
1537                             auto factory = new WrappingFactory!(GenericFactoryImpl!(ReturnType!overload))(
1538                                 new GenericFactoryImpl!(ReturnType!overload)(locator)
1539                             );
1540 
1541                             if (factory !is null) {
1542                                 auto params = makeFunctionParameterReferences!overload.expand;
1543 
1544                                 debug(annotationScanDebug) trace(fullyQualifiedName!T, ".", member, " is annotated with @component annotation, using it as constructor for component with args ", params);
1545                                 static if (isModule!T) {
1546                                     auto instanceFactory = functionInstanceFactory(&overload, params);
1547                                 } else static if (__traits(isStaticFunction, overload)) {
1548                                     auto instanceFactory = factoryMethodBasedFactory!(T, member)(params);
1549                                 } else {
1550                                     auto instanceFactory = factoryMethodBasedFactory!(T, member)(lref!T, params);
1551                                 }
1552 
1553                                 import aermicioi.aedi.storage.decorator : Decorator;
1554 
1555                                 static if (is(typeof(factory) : Decorator!X, X : GenericFactory!Z, Z)) {
1556                                     factory.decorated.setInstanceFactory = instanceFactory;
1557                                 } else static if (is(typeof(factory) : GenericFactory!Z, Z) && !is(Z == Object)) {
1558                                     factory.setInstanceFactory = instanceFactory;
1559                                 }
1560 
1561                                 ComponentStoringResult result;
1562                                 result = ByMethodComponentStoringPolicy.store!overload(factory, locator, storage);
1563 
1564                                 if (result !is ComponentStoringResult.init) {
1565                                     AliasAware!string container = (delegate AliasAware!string () @trusted => cast(AliasAware!string) result.storage)();
1566 
1567                                     if (container !is null) {
1568                                         ByTypeAliasingPolicy.link!(ReturnType!overload)(result.identity, container);
1569                                     }
1570                                 } else {
1571 
1572                                     ByTypeComponentStoringPolicy.store!(ReturnType!overload)(factory, locator, storage);
1573                                 }
1574                             }
1575                         }
1576                     }}
1577                 }}
1578             }
1579         }}
1580     }
1581 }
1582 
1583 /**
1584 Implementation of field scanning configurator policy, with built in field configurators.
1585 **/
1586 alias FieldScanningConfiguratorPolicyImpl = FieldScanningConfiguratorPolicy!(
1587         SetterFieldConfiguratorPolicy,
1588         CallbackFieldConfiguratorPolicy,
1589         AutowiredFieldConfiguratorPolicy
1590     );
1591 
1592 /**
1593 Implementation of method scanning configurator policy, with built in method configurators.
1594 **/
1595 alias MethodScanningConfiguratorPolicyImpl = MethodScanningConfiguratorPolicy!(
1596         ConstructorMethodConfiguratorPolicy,
1597         AutowiredConstructorMethodConfiguratorPolicy,
1598         SetterMethodConfiguratorPolicy,
1599         CallbackMethodConfiguratorPolicy,
1600         AutowiredMethodConfiguratorPolicy
1601     );
1602 
1603 /**
1604 Implementation of configurator policy, with built in configurators
1605 **/
1606 alias ConfiguratorPolicyImpl = ChainedConfiguratorPolicy!(
1607             FieldScanningConfiguratorPolicyImpl,
1608             MethodScanningConfiguratorPolicyImpl,
1609             AllocatorConfiguratorPolicy,
1610             CallbackFactoryConfiguratorPolicy,
1611             ValueFactoryConfiguratorPolicy,
1612             GenericConfigurerConfiguratorPolicy
1613         );
1614 
1615 /**
1616 Implementation of factory policy, with built in factory creators
1617 **/
1618 alias FactoryPolicyImpl = FallbackFactoryPolicy!(
1619     GenericFactoryPolicy,
1620     GenericFactoryAnnotationPolicy
1621 );
1622 
1623 /**
1624 Implementation of type to type factory transformer, with built in funcionality
1625 **/
1626 alias TypeTransformerImpl = TypeTransformer!(
1627         FactoryPolicyImpl,
1628         ConfiguratorPolicyImpl
1629     );
1630 
1631 /**
1632 Implementation of object wrapping factory wrapping TypeTransformerImpl
1633 **/
1634 alias ObjectFactoryTransformerImpl =
1635     ObjectFactoryTransformer!(
1636         TypeTransformerImpl
1637     );
1638 
1639 /**
1640 Implementation of module container adder, featuring built in scanners
1641 **/
1642 alias ModuleContainerAdderImpl(TransformerPolicy = ObjectFactoryTransformerImpl) = ModuleContainerAdder!(
1643         IgnoringContainerAdder!("std",
1644             ChainedContainerAdder!(
1645                 IgnoringContainerAdder!("std", TypeContainerAdder!TransformerPolicy),
1646                 IgnoringContainerAdder!("std", InnerTypeContainerAdder!(TypeContainerAdder!TransformerPolicy)),
1647                 IgnoringContainerAdder!("std", FactoryMethodContainerAdder!()),
1648             )
1649         )
1650     );
1651 
1652 /**
1653 Customizable implementation of container adder, with built in functionality
1654 **/
1655 alias ContainerAdderImpl(TransformerPolicy = ObjectFactoryTransformerImpl) = ChainedContainerAdder!(
1656         IgnoringContainerAdder!("std", TypeContainerAdder!TransformerPolicy),
1657         IgnoringContainerAdder!("std", InnerTypeContainerAdder!(TypeContainerAdder!TransformerPolicy)),
1658         IgnoringContainerAdder!("std", FactoryMethodContainerAdder!()),
1659         ModuleContainerAdderImpl!TransformerPolicy
1660     );
1661 
1662 /**
1663 Template for defining scanning functions instantiated with particular container adder policy.
1664 
1665 The functions defined in this template mixin are the entry point for running scans over symbols that
1666 are desired to be added into a container. The template will instantiate $(D_INLINECODE scan) family of functions
1667 that will use passed container adder policy to scan symbols passed to them. It is advised to define your own
1668 set of scanning methods in case when additional scanning and transformation logic is expected.
1669 **/
1670 @safe mixin template Scanner(ContainerAdderPolicy) {
1671 
1672     /**
1673     Scan symbol T for possible components using ContainerAdderPolicy
1674 
1675     Params:
1676         storage = storage that will contain component factories
1677         locator = locator of components used to by component factories
1678     **/
1679     void scan(alias T)(Storage!(ObjectFactory, string) storage, Locator!() locator) {
1680         debug(annotationScanDebug) trace(fullyQualifiedName!T, " will be scanned for possible components.");
1681 
1682         ContainerAdderPolicy.scan!T(locator, storage);
1683     }
1684 
1685     /**
1686     ditto
1687     **/
1688     void scan(alias T, X...)(Storage!(ObjectFactory, string) storage, Locator!() locator) {
1689 
1690         scan!T(storage, locator);
1691 
1692         static if (X.length > 0) {
1693 
1694             scan!X(storage, locator);
1695         }
1696     }
1697 
1698     /**
1699     Scan symbol T for possible components using ContainerAdderPolicy
1700 
1701     Params:
1702         storage = identity by which to search storage in locator, that will be used to store components
1703         locator = locator of components used to by component factories
1704     **/
1705     void scan(alias T)(string storage, Locator!() locator) {
1706 
1707         scan!T(locator.locate!(Storage!(ObjectFactory, string))(storage), locator);
1708     }
1709 
1710     /**
1711     ditto
1712     **/
1713     void scan(alias T, X...)(string storage, Locator!() locator) {
1714 
1715         scan!(T, X)(locator.locate!(Storage!(ObjectFactory, string))(storage), locator);
1716     }
1717 
1718     /**
1719     Scan symbol T for possible components using ContainerAdderPolicy
1720 
1721     Params:
1722         container = container where to store and from which to locate dependencies for components
1723     **/
1724     void scan(alias T)(ConfigurableContainer container) {
1725 
1726         scan!T(container, container);
1727     }
1728 
1729 
1730     void scan(alias T, St : Storage!(ObjectFactory, string) = Storage!(ObjectFactory, string))(Locator!() locator) {
1731 
1732         scan!T(locator.locate!St, locator);
1733     }
1734 
1735     /**
1736     ditto
1737     **/
1738     void scan(alias T, St : Storage!(ObjectFactory, string), X...)(Locator!() locator) {
1739 
1740         scan!(T, St)(locator);
1741 
1742         static if (X.length > 0) {
1743 
1744             scan!X(locator);
1745         }
1746     }
1747 
1748     /**
1749     ditto
1750     **/
1751     void scan(alias T, X...)(Locator!() locator) {
1752         scan!T(locator);
1753 
1754         static if (X.length > 0) {
1755 
1756             scan!X(locator);
1757         }
1758     }
1759 }
1760 
1761 /**
1762 Default implementation of $(D_INLINECODE scan) family of functions featuring all scanning features provided by library.
1763 **/
1764 mixin Scanner!(ContainerAdderImpl!());
1765 
1766 /**
1767 A small utility function that will resolve method arguments using a locator and look also for annotations on arguments.
1768 
1769 Params:
1770     locator = locator used to prepare list of arguments for function
1771     overload = function for which to prepare arguments. The func itself must not be an overloaded set of functions.
1772     args = list of args that should override existing references by type of argument.
1773 
1774 Returns:
1775     a tuple with all required arguments prefilled.
1776 **/
1777 auto prepare(alias overload, Args...)(Locator!() locator, out Parameters!overload parameters, Args args) {
1778     import std.traits : FunctionTypeOf;
1779 
1780     auto references = makeFunctionParameterReferences!(overload)().expand;
1781     static foreach (index, arg; parameters) {
1782         static if (is(Args[index] == typeof(arg))) {
1783             arg = args[index];
1784         } else {
1785             arg = references[index].resolve!(typeof(arg))(locator);
1786         }
1787     }
1788 }
1789 
1790 private alias makeFunctionParameterReferences(alias FunctionType) = aermicioi.aedi.factory.reference.makeFunctionParameterReferences!(FunctionType, transformToReference);
1791 
1792 auto transformToReference(string reference, string symbol) {
1793     import aermicioi.aedi.factory.reference : transformToBasic = transformToReference;
1794     import std.range : chain, only, enumerate;
1795     import std.algorithm : joiner, map, substitute;
1796     import std.array : array;
1797     import std.utf : byChar;
1798 
1799     string delegate (string) toTypeGen = (s) => "toType!(" ~ s ~ ")";
1800     string delegate (string, string) typeEnforcedRefGen = (t, s) => "typeEnforcedRef!(" ~ toTypeGen(t) ~ ")(" ~ s ~ ")";
1801     string delegate (string) lrefGen = (s) => s ~ ".lref";
1802     string delegate (string, string) alternateGen = (f, s) => f ~ ".alternate(" ~ s ~ ")";
1803 
1804     return transformToBasic(reference, symbol) ~ "
1805                 import std.meta : AliasSeq;
1806                 import aermicioi.aedi.configurer.annotation.annotation : isQualifierAnnotation;
1807                 alias Qualifiers = AliasSeq!(__traits(getAttributes, " ~ symbol ~ "));
1808                 static foreach (index; 0 .. Qualifiers.length) {
1809                     static if (isQualifierAnnotation!(Qualifiers[index])) {
1810                         " ~ reference ~ " = " ~ alternateGen(typeEnforcedRefGen(symbol, lrefGen("Qualifiers[index].id")), typeEnforcedRefGen(symbol, reference)) ~ ";
1811                     }
1812                 }
1813             ";
1814 }
1815 
1816 private template allUDAs(alias symbol) {
1817     alias allUDAs = AliasSeq!(__traits(getAttributes, symbol));
1818 }