1 /**
2 
3 License:
4 	Boost Software License - Version 1.0 - August 17th, 2003
5     
6     Permission is hereby granted, free of charge, to any person or organization
7     obtaining a copy of the software and accompanying documentation covered by
8     this license (the "Software") to use, reproduce, display, distribute,
9     execute, and transmit the Software, and to prepare derivative works of the
10     Software, and to permit third-parties to whom the Software is furnished to
11     do so, all subject to the following:
12     
13     The copyright notices in the Software and this entire statement, including
14     the above license grant, this restriction and the following disclaimer,
15     must be included in all copies of the Software, in whole or in part, and
16     all derivative works of the Software, unless such copies or derivative
17     works are solely in the form of machine-executable object code generated by
18     a source language processor.
19     
20     THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21     IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22     FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
23     SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
24     FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
25     ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
26     DEALINGS IN THE SOFTWARE.
27 
28 Authors:
29 	Alexandru Ermicioi
30 **/
31 module aermicioi.aedi.factory.generic_factory;
32 
33 
34 import aermicioi.aedi.exception;
35 import aermicioi.aedi.factory.factory;
36 import aermicioi.aedi.factory.reference;
37 import aermicioi.aedi.storage.decorator;
38 import aermicioi.aedi.storage.locator;
39 import aermicioi.aedi.storage.locator_aware;
40 import aermicioi.aedi.storage.wrapper;
41 import aermicioi.util.traits;
42 
43 import std.conv : to;
44 import std.meta;
45 import std.traits;
46 import std.typecons;
47 
48 /**
49 A property configurer, has the purpose to modify data of type T according to some logic encapsulated in it.
50 
51 **/
52 interface PropertyConfigurer(T) {
53     
54     public {
55         
56         /**
57         Accepts a reference to an object that is to be configured by the configurer.
58         
59         Params:
60         	object = An object of type T, that will be configured
61         **/
62         void configure(ref T object);
63     }
64 }
65 
66 /**
67 An instance factory, instantiates data of type T.
68 **/
69 interface InstanceFactory(T) {
70     
71     public {
72         
73         /**
74         Create a new instance of object of type T.
75         
76         Returns:
77             T instantiated component
78         **/
79         T factory();
80     }
81 }
82 
83 /**
84 Interface for objects that are aware of an instance factory
85 and can use it to instantiate a component.
86 **/
87 interface InstanceFactoryAware(T) {
88     public {
89         
90         @property {
91         	/**
92             Sets the constructor of new object.
93             
94             Params:
95             	factory = a factory of objects of type T.
96         	
97         	Returns:
98     			The InstanceFactoryAware
99             **/
100             InstanceFactoryAware!T setInstanceFactory(InstanceFactory!T factory);
101         }
102     }
103 }
104 
105 /**
106 Interface for objects that are aware of a set of property configurers
107 and can use them to configure some component.
108 **/
109 interface PropertyConfigurersAware(T) {
110     public {
111         /**
112         Adds an configurer to the PropertyConfigurersAware.
113         
114         Params:
115         	configurer = a configurer that will be invoked after factory of an object.
116         	
117     	Returns:
118     		The PropertyConfigurersAware instance
119         **/
120         PropertyConfigurersAware!T addPropertyConfigurer(PropertyConfigurer!T configurer);
121     }
122 }
123 /**
124 A generic factory, is a factory that instantiates data of type T using InstanceFactory and a list of PropertyConfigurers.
125 
126 A generic factory, is a factory that instantiates data of type T using InstanceFactory and a list of PropertyConfigurers.
127 It can optionally provide a Locator!() object to InstanceFactory and PropertyConfigurer to be used as a source of data. 
128 **/
129 interface GenericFactory(T) : Factory!T, InstanceFactoryAware!T, PropertyConfigurersAware!T {
130     
131     public {
132         
133         @property {
134             
135             alias locator = Factory!T.locator;
136             
137             /**
138             Get the GenericFactory locator.
139             
140             Returns:
141             	Locator!() the locator that should be used by underlying constructor or property configurer.
142             **/
143             Locator!() locator();
144         }
145     }
146 }
147 
148 /**
149 A concrete implementation of GenericFactory interface.
150 **/
151 class GenericFactoryImpl(T) : GenericFactory!T, LocatorAware!() {
152     
153     private {
154         Locator!() locator_;
155         
156         InstanceFactory!T factory_;
157         
158         PropertyConfigurer!T[] configurers;
159     }
160     
161     public {
162         
163         /**
164             Constructor for GenericFactoryImpl
165             
166             Params:
167                 locator = the locator used by constructor to fetch dependencies of the created object
168         **/
169         this(Locator!() locator) {
170             this.locator = locator;
171             
172             static if (hasDefaultCtor!T) {
173                 
174                 this.setInstanceFactory(
175                     new DefaultConstructorBasedFactory!T
176                 );
177             }
178         }
179         
180         /**
181         Create a new instance of object of type T using provided instance factory and property configurers.
182         
183         Returns:
184             T instantiated component
185         **/
186         T factory() {
187             T instance;
188             
189             if (this.factory_ !is null) {
190                 instance = this.factory_.factory;
191             } else {
192                 
193                 throw new AediException("Failed to construct object due to no constructor");
194             }
195 
196             foreach (key, configurer; this.configurers) {
197                 configurer.configure(instance);
198             }
199             
200             return instance;
201         }
202         
203         @property {
204             
205             /**
206             Sets the constructor of new object.
207             
208             Params:
209             	factory = a factory of objects of type T.
210         	
211         	Returns:
212     			The InstanceFactoryAware
213             **/
214             GenericFactory!T setInstanceFactory(InstanceFactory!T factory) {
215                 this.factory_ = factory;
216                 
217                 return this;
218             }
219             
220             /**
221                 Set locator
222                 
223                 Params: 
224                     locator = the locator used to fetch created's object dependencies
225                 Returns:
226                     typeof(this)
227             **/
228             GenericFactoryImpl!T locator(Locator!() locator) {
229                 this.locator_ = locator;
230                 return this;
231             }
232             
233             /**
234                 Get locator
235                 
236                 Returns:
237                     Locator!()
238             **/
239             Locator!() locator() {
240                 return this.locator_;
241             }
242             
243             /**
244     		Get the type info of object that is created.
245     		
246     		Returns:
247     			TypeInfo object of created object.
248     		**/
249     		TypeInfo type() {
250     		    return typeid(T);
251     		}
252         }
253         
254         /**
255         Adds an configurer to the PropertyConfigurersAware.
256         
257         Params:
258         	configurer = a configurer that will be invoked after factory of an object.
259         	
260     	Returns:
261     		The PropertyConfigurersAware instance
262         **/
263         GenericFactory!T addPropertyConfigurer(PropertyConfigurer!T configurer) {
264             
265             this.configurers ~= configurer;
266             
267             return this;
268         }
269     }
270     
271 }
272 
273 /**
274 ditto
275 **/
276 GenericFactory!T genericFactory(T)(Locator!() locator) {
277     return new GenericFactoryImpl!T(locator);
278 }
279 
280 /**
281 ParameterHolder Stores a set of Args for futher usage in it's subclasses.
282 
283 Params:
284     Args = a type tuple of args that ParameterHolder can hold.
285 **/
286 abstract class ParameterHolder(Args...) : LocatorAware!() {
287     
288     protected {
289         Tuple!Args args_;
290         Locator!() locator_;
291     }
292     
293     public {
294         
295         static if (Args.length > 0) {
296 
297             /**
298                 Set args
299                 
300                 Params: 
301                     args = arguments that parameter holder should hold.
302                 Returns:
303                     typeof(this)
304             **/ 
305             ParameterHolder args(ref Args args) @safe nothrow {
306             	this.args_ = tuple(args);
307             
308             	return this;
309             }
310         }
311         
312         /**
313             Get args
314             
315             Returns:
316                 Tuple!Args arguments stored by argument holder
317         **/
318         Tuple!Args args() @safe nothrow {
319         	return this.args_;
320         } 
321     
322         @property {
323             /**
324     		Sets the locator that will be used by configurer to fetch object referenced in argument list.
325     		
326     		Params:
327     			locator = the (service) locator that will be used to fetch required objects.
328     		
329     		Returns:
330     			The ParameterHolder instance.
331     		**/
332             ParameterHolder!Args locator(Locator!() locator)  {
333             	this.locator_ = locator;
334             
335             	return this;
336             }
337             
338             /**
339                 Get locator
340                 
341                 Returns:
342                     Locator!()
343             **/
344             Locator!() locator() @safe nothrow {
345             	return this.locator_;
346             }
347         }
348     }
349 }
350 
351 /**
352 Calls aggregate's method with a set of arguments.
353 
354 Encapsulates a call to aggregate's method, with a set of arguments.
355 The algorithm that calls aggregate's method, will automatically replace
356 references from args list with data extracted from container, casted to 
357 type that is extracted from method's signature.
358 
359 Params:
360     T = the aggregate type
361     property = method that will be called
362     Args = type tuple of args that method can be called with.
363 **/
364 class MethodConfigurer(T, string property, Args...) : ParameterHolder!Args, PropertyConfigurer!T
365 	if (
366 	    isMethodCompatible!(T, property, Args)
367     ) {
368     
369     public {
370         
371         /**
372             Constructor for MethodConfigurer!(T, property, Args)
373             
374             Params: 
375                 args = list of arguments passed to T's method
376         **/
377         this(ref Args args) {
378             this.args(args);
379         }
380         
381         /**
382         See PropertyConfigurer interface
383         
384         Throws:
385             InvalidCastException when extracted data by reference, is not of type expected by argument
386             of aggregate's method
387         **/
388         void configure(ref T obj) {
389             
390             try {
391                 
392                 alias ArgTuple = Parameters!(
393                     Filter!(
394                         partialSuffixed!(
395                             isArgumentListCompatible, 
396                             Args
397                         ), 
398                         getOverloads!(
399                             T, 
400                             property
401                         )
402                     )[0]
403                 );
404                 Tuple!ArgTuple parameters;
405                 
406                 foreach (index, ref parameter; parameters) {
407                     
408                     parameter = args[index].resolve!(typeof(parameter))(this.locator);
409                 }
410                 __traits(getMember, obj, property)(parameters.expand);
411             } catch (Exception e) {
412                 throw new PropertyConfigurerException("Error occurred during call of " ~ name!T ~ "." ~ property, e);
413             }
414         }
415     }
416 }
417     
418 /**
419 ditto
420 **/
421 auto methodConfigurer(string property, T, Args...)(Locator!() locator, auto ref Args args) 
422     if (!isField!(T, property)) {
423     mixin assertObjectMethodCompatible!(T, property, Args);
424     
425     auto propertySetter = new MethodConfigurer!(T, property, Args)(args);
426     propertySetter.locator = locator;
427     
428     return propertySetter;
429 }
430 
431 /**
432 Sets aggregate's field to a value.
433 
434 Encapsulates logic that sets aggregates field to a certain value.
435 If argument that is contained by configurer is a reference, it will be automatically
436 replaced with value extracted from locator, and set to aggregate's field.
437 **/
438 class FieldConfigurer(T, string property, Arg) : ParameterHolder!Arg, PropertyConfigurer!T
439 	if (
440 	    isFieldCompatible!(T, property, Arg)
441     ) {
442     
443     public {
444         /**
445             Constructor for MethodConfigurer!(T, property, Args)
446             
447             Params: 
448                 arg = list of arguments passed to T's method
449         **/
450         this(ref Arg arg) {
451             this.args(arg);
452         }
453         
454         /**
455         See PropertyConfigurer interface
456         
457         Throws:
458             InvalidCastException when extracted data by reference, is not of type expected by argument
459             of aggregate's field
460         **/
461         void configure(ref T obj) {
462             
463             try {
464             
465                 __traits(getMember, obj, property) = args[0].resolve!(
466                     typeof(__traits(getMember, obj, property))
467                 )(
468                     this.locator
469                 );
470             } catch (Exception e) {
471                 
472                 throw new PropertyConfigurerException("Error occurred during set of " ~ name!T ~ "." ~ property, e);
473             }
474         }
475     }
476 }
477     
478 /**
479 ditto
480 **/
481 auto fieldConfigurer(string property, T, Arg)(Locator!() locator, auto ref Arg arg)
482     if (isField!(T, property)) {
483     mixin assertFieldCompatible!(T, property, Arg);
484     
485     auto propertySetter = new FieldConfigurer!(T, property, Arg)(arg);
486     propertySetter.locator = locator;
487     
488     return propertySetter;
489 }
490 
491 /**
492 Instantiates an aggregate using it's constructor with no arguments.
493 **/
494 class DefaultConstructorBasedFactory(T) : InstanceFactory!T 
495     if (
496         hasDefaultCtor!T
497     ) {
498     
499     public {
500         /**
501         Create a new instance of object of type T.
502         
503         Returns:
504             T instantiated component
505         **/
506         T factory() {
507             
508             try {
509                 static if (is(T : Object)) {
510                     return new T();
511                 } else {
512                     return T.init;
513                 }
514             } catch (Exception e) {
515                 throw new InstanceFactoryException("Error occurred during instantiation of " ~ name!T, e);
516             }
517         }
518     }
519 }
520     
521 /**
522 Instantiates aggregate using it's constructor with args.
523 
524 Encapsulates construction of aggregate using a constructor, with args.
525 Arguments from argument list that are references, are automatically 
526 replaced with data extracted from locator.
527 
528 Params:
529     T = aggregate type
530     Args = type tuple of args that are passed to T's constructor
531 **/
532 class ConstructorBasedFactory(T, Args...) : ParameterHolder!Args, InstanceFactory!T
533 	if (
534 	    isObjectConstructorCompatible!(T, Args)
535 	) {
536     
537     public {
538         /**
539             Constructor for ConstructorBasedFactory!(T, Args)
540             
541             Params: 
542                 args = arguments used for constructor
543         **/
544         this(ref Args args) {
545             this.args(args);
546         }
547         
548         /**
549         See InstanceFactory interface
550         
551         Throws:
552             InvalidCastException when extracted data by reference, is not of type expected by argument
553             of aggregate's constructor
554         **/
555         T factory() {
556             
557             try {
558                 
559                 alias ConstructorArgs = staticMap!(Unqual,
560                     Parameters!(
561                         Filter!(
562                             partialSuffixed!(
563                                 isArgumentListCompatible,
564                                 Args
565                             ), 
566                             __traits(getOverloads, T, "__ctor")
567                         )[0]
568                     )
569                 );
570                 
571                 Tuple!ConstructorArgs parameters;
572                 
573                 foreach (index, ref parameter; parameters) {
574                     parameter = this.args[index].resolve!(typeof(parameter))(this.locator);
575                 }
576                 
577                 static if (is(T : Object)) {
578                     return new T(parameters.expand);
579                 } else {
580                     return T(parameters.expand);
581                 }
582             } catch (Exception e) {
583                 
584                 throw new InstanceFactoryException("Error occurred during instantiation of " ~ name!T, e);
585             }
586         }
587     }
588 }
589 	
590 /**
591 ditto
592 **/
593 auto constructorBasedFactory(T, Args...)(Locator!() locator, auto ref Args args) {
594     mixin assertObjectConstructorCompatible!(T, Args);
595     auto constructor = new ConstructorBasedFactory!(T, Args)(args);
596     
597     constructor.locator = locator;
598     
599     return constructor;
600 }
601 	
602 /**
603 Instantiates an aggregate using a method from other aggregate (factory method pattern).
604 
605 Encapsulates construction of aggregate using factory method.
606 Arguments that are references, will be replaced with data extracted
607 from locator, and passed to factory's method.
608 In case when method is not static member, the algorithm will use 
609 an instantiaton of factory passed to it, or extracted from locator
610 if a reference is passed.
611 
612 Params:
613     T = factory that is used to instantiate aggregate using it's method
614     method = the name of method used to instantiate aggregate
615     W = the factory T, or a LocatorReference to the factory.
616     Args = type tuple of arguments passed to factory.
617 **/
618 class FactoryMethodBasedFactory(T, string method, W, Args...) : 
619     ParameterHolder!Args, 
620     InstanceFactory!(ReturnType!(getCompatibleOverload!(T, method, Args)))
621     if (
622         (is(W : RuntimeReference) || is(W : T)) &&
623         isMethodCompatible!(T, method, Args) &&
624         isAggregateType!(ReturnType!(getCompatibleOverload!(T, method, Args)))
625     ) {
626         
627     static if (!__traits(isStaticFunction, getCompatibleOverload!(T, method, Args))) {
628         
629         private {
630             W fact;
631         }
632         
633         public {
634             /**
635                 Constructor for FactoryMethodBasedFactory!(T, method, W, Args)
636                 
637                 Params: 
638                     fact = factory used to create object
639                     args = arguments passed to factory's method
640             **/
641             this(ref W fact, ref Args args) {
642                 this.args(args);
643                 this.fact = fact;
644             }
645         }
646     } else {
647         
648         /**
649             Constructor for FactoryMethodBasedFactory!(T, method, W, Args)
650             
651             Params: 
652                 args = arguments passed to factory's static method
653         **/
654         this(ref Args args) {
655             this.args(args);
656         }
657     }
658         
659     private {
660         
661         alias Z = ReturnType!(getCompatibleOverload!(T, method, Args));
662     }
663     
664     public {
665         /**
666         See InstanceFactory interface
667         
668         Throws:
669             InvalidCastException when extracted data by reference, is not of type expected by argument
670             factory's method, or when factory is referenced, and the object referenced in locator is not
671             of factory's type T.
672         Returns:
673             Z created object
674         **/
675         Z factory() {
676             
677             try {
678                 
679                 alias FactoryMethodParameters = Parameters!(
680                     Filter!(
681                         partialSuffixed!(
682                             isArgumentListCompatible, 
683                             Args
684                         ), __traits(
685                             getOverloads, 
686                             T, 
687                             method
688                         )
689                     )[0]
690                 );
691                 
692                 Tuple!FactoryMethodParameters parameters;
693                 
694                 foreach (index, ref parameter; parameters) {
695                     parameter = this.args[index].resolve!(typeof(parameter))(this.locator);
696                 }
697                 
698                 static if (!__traits(isStaticFunction, getCompatibleOverload!(T, method, Args))) {
699     
700                     return __traits(getMember, this.fact.resolve!(T)(this.locator), method)(parameters.expand);
701                 } else {
702     
703                     return __traits(getMember, T, method)(parameters.expand);
704                 }
705             } catch (Exception e) {
706                 
707                 throw new InstanceFactoryException(
708                     "Error occurred during instantiation of " ~ 
709                     name!T ~ 
710                     " using factory method of " 
711                     ~ name!T ~ 
712                     "." ~ 
713                     method, 
714                     e
715                 );
716             }
717         }
718     }
719 }
720     
721 /**
722 ditto
723 **/
724 auto factoryMethodBasedFactory
725         (T, string method, W, Args...)
726         (Locator!() locator, auto ref W factoryMethod, auto ref Args args)
727     if (
728         isNonStaticMethodCompatible!(T, method, Args) &&
729         (is(W : T) || is(W : RuntimeReference))
730     ) {
731         
732     auto constructor = new FactoryMethodBasedFactory!(T, method, W, Args)(factoryMethod, args);
733     
734     constructor.locator = locator;
735     
736     return constructor;
737 }
738 
739 /**
740 ditto
741 **/
742 auto factoryMethodBasedFactory(T, string method, Args...)(Locator!() locator, auto ref Args args)
743     if (
744         isStaticMethodCompatible!(T, method, Args)
745     ) {
746     auto constructor = new FactoryMethodBasedFactory!(T, method, T, Args)(args);
747     
748     constructor.locator = locator;
749     
750     return constructor;
751 }
752     
753 /**
754 Instantiates data of type T using a delegate or function.
755 
756 Encapsulates data's construction logic using a delegate.
757 The algorithm uses a delegate to create required data, 
758 with a set of Args that are passed to delegate, and a locator
759 for dependency fetching. 
760 
761 Params:
762     T = the constructed aggregate
763     Args = type tuple of arguments passed to delegate for aggregate's construction. 
764 **/
765 class CallbackFactory(T, Dg, Args...) : ParameterHolder!Args, InstanceFactory!T
766     if ((is(Dg == T delegate (Locator!(), Args)) || is(Dg == T function (Locator!(), Args)))) {
767     
768     private {
769         Dg dg;
770     }
771     
772     public {
773         /**
774             Constructor for CallbackFactory!(T, Dg, Args)
775             
776             Params: 
777                 dg = delegate used to create object
778                 args = arguments passed to delegate
779         **/
780         this(Dg dg, ref Args args) {
781             this.dg = dg;
782             this.args(args);
783         }
784         
785         /**
786         See InstanceFactory interface
787         **/
788         T factory() {
789             try {
790                 
791                 return this.dg(this.locator_, args.expand);
792             } catch (Exception e) {
793                 
794                 throw new InstanceFactoryException(
795                     "Error occurred during instantiation of " ~ 
796                     name!T ~ 
797                     " using callback factory", 
798                     e
799                 );
800             }
801         }
802     }
803 }
804     
805 /**
806 ditto
807 **/
808 auto callbackFactory(T, Args...)(Locator!() locator, T delegate(Locator!(), Args) dg, auto ref Args args) {
809     auto constr = new CallbackFactory!(T, T delegate(Locator!(), Args), Args)(dg, args);
810     constr.locator = locator;
811     return constr;
812 }
813     
814 /**
815 ditto
816 **/
817 auto callbackFactory(T, Args...)(Locator!() locator, T function(Locator!(), Args) dg, auto ref Args args) {
818     auto constr = new CallbackFactory!(T, T function(Locator!(), Args), Args)(dg, args);
819     constr.locator = locator;
820     return constr;
821 }
822 
823 /**
824 Configures/modifies data of type T with help of a delegate or function.
825 
826 Encapsulates data configuration logic using a delegate.
827 The algorithm calls delegate, with a locator, a set of Args,
828 and configured data, in order to modify the data
829 somehow.
830 
831 Note:
832     If data is not a reference type it is recommended to pass it by reference
833     in order to avoid receiving of a copy and not original one in delegate.
834 Params:
835     T = the aggregate
836     Args = type tuple of arguments used by delegate for customization.
837 **/
838 class CallbackConfigurer(T, Dg, Args...) : ParameterHolder!Args, PropertyConfigurer!T 
839     if (
840         is(Dg == void delegate (Locator!(), T, Args)) || 
841         is(Dg == void function (Locator!(), T, Args)) ||
842         is(Dg == void delegate (Locator!(), ref T, Args)) || 
843         is(Dg == void function (Locator!(), ref T, Args))
844     ) {
845     
846     private {
847         Dg dg;
848     }
849     
850     public {
851         /**
852             Constructor for CallbackConfigurer!(T, Dg, Args)
853             
854             Params: 
855                 dg = delegate used to configure the created object
856                 args = arguments passed to delegate
857         **/
858         this(Dg dg, ref Args args) {
859             this.dg = dg;
860             this.args(args);
861         }
862         
863         /**
864         Accepts a reference to an object that is to be configured by the configurer.
865         
866         Params:
867         	object = An object of type T, that will be configured
868         **/
869         void configure(ref T object) {
870             
871             try {
872             
873                 return this.dg(this.locator_, object, args.expand);
874             } catch (Exception e) {
875             	throw new PropertyConfigurerException("Error occurred during callback configuration of " ~ name!T, e);
876             }
877         }
878     }
879 }
880     
881 /**
882 ditto
883 **/
884 auto callbackConfigurer(T, Args...)(Locator!() locator, void delegate(Locator!(), T, Args) dg, auto ref Args args) {
885     auto constr = new CallbackConfigurer!(T, void delegate(Locator!(), T, Args), Args)(dg, args);
886     constr.locator = locator;
887     return constr;
888 }
889     
890 /**
891 ditto
892 **/
893 auto callbackConfigurer(T, Args...)(Locator!() locator, void function(Locator!(), T, Args) dg, auto ref Args args) {
894     auto constr = new CallbackConfigurer!(T, void function(Locator!(), T, Args), Args)(dg, args);
895     constr.locator = locator;
896     return constr;
897 }
898 
899 /**
900 ditto
901 **/
902 auto callbackConfigurer(T, Args...)(Locator!() locator, void delegate(Locator!(), ref T, Args) dg, auto ref Args args) {
903     auto constr = new CallbackConfigurer!(T, void delegate(Locator!(), ref T, Args), Args)(dg, args);
904     constr.locator = locator;
905     return constr;
906 }
907     
908 /**
909 ditto
910 **/
911 auto callbackConfigurer(T, Args...)(Locator!() locator, void function(Locator!(), ref T, Args) dg, auto ref Args args) {
912     auto constr = new CallbackConfigurer!(T, void function(Locator!(), ref T, Args), Args)(dg, args);
913     constr.locator = locator;
914     return constr;
915 }
916 
917 
918 /**
919 Instantiates a component using a value as basis.
920 
921 Instantiates a component using a value as basis.
922 As a consequence, any reference based type will 
923 point to same content when it is instantiated 
924 multiple times. 
925 **/
926 class ValueInstanceFactory(T) : InstanceFactory!T {
927     private {
928         T initial_;
929     }
930     
931     public {
932         /**
933             Constructor for ValueInstanceFactory!T
934             
935             Params: 
936                 initial = argument that is to be passed as created object
937         **/
938         this(T initial) {
939             this.initial = initial;
940         }
941         
942         @property {
943 
944             /**
945                 Set initial
946                 
947                 Params: 
948                     initial = value which will be passed as created component
949                 Returns:
950                     typeof(this)
951             **/
952         	ValueInstanceFactory!T initial(T initial) @safe nothrow {
953         		this.initial_ = initial;
954         	
955         		return this;
956         	}
957         	
958             /**
959                 Get initial
960                 
961                 Returns:
962                     T
963             **/
964         	T initial() @safe nothrow {
965         		return this.initial_;
966         	}
967         }
968         
969         /**
970         Create a new instance of object of type T.
971         
972         Returns:
973             T instantiated component
974         **/
975         T factory() {
976             return this.initial();
977         }
978     }
979 }
980 
981 /**
982 InstanceFactory that delegates the task of instantiating a component
983 to some third party factory.
984 **/
985 class DelegatingInstanceFactory(T, X : T) : InstanceFactory!T, MutableDecorator!(Factory!X) {
986     
987     private {
988         Factory!X decorated_;
989     }
990     
991     public {
992         
993         /**
994             Default constructor for DelegatingInstanceFactory!(T, X)
995         **/
996         this() {
997             
998         }
999         
1000         /**
1001             Constructor for DelegatingInstanceFactory!(T, X)
1002             
1003             Params: 
1004                 factory = the factory to which this instance will delegate the task of creating a component
1005         **/
1006         this(Factory!X factory) {
1007             this.decorated = factory;
1008         }
1009         
1010         @property {
1011             /**
1012             Set the decorated object for decorator.
1013             
1014             Params:
1015                 decorated = decorated data
1016             
1017             Returns:
1018             	this
1019             **/
1020         	DelegatingInstanceFactory!(T, X) decorated(Factory!X decorated) @safe nothrow {
1021         		this.decorated_ = decorated;
1022         	
1023         		return this;
1024         	}
1025         	
1026         	/**
1027             Get the decorated object.
1028             
1029             Returns:
1030             	T decorated object
1031             **/
1032         	Factory!X decorated() @safe nothrow {
1033         		return this.decorated_;
1034         	}
1035         }
1036         
1037         /**
1038         Create a new instance of object of type T.
1039         
1040         Returns:
1041             T instantiated component
1042         **/
1043         T factory() {
1044             return this.decorated.factory();
1045         }
1046     }
1047 }
1048 
1049 /**
1050 An check if the argument list passed to ConstructorBasedFactory or MethodConfigurer is compatible with signature of underlying
1051 method or constructor.
1052 
1053 Note:
1054 	For now it checks if the lengths are equal. For future it should also check if types are compatible.
1055 **/
1056 template isArgumentListCompatible(alias func, ArgTuple...) 
1057 	if (isSomeFunction!func) {
1058     bool isArgumentListCompatible() {
1059         alias FuncParams = Parameters!func;
1060         alias Required = Filter!(partialSuffixed!(isValueOfType, void), ParameterDefaults!func);
1061        
1062         static if ((ArgTuple.length < Required.length) || (ArgTuple.length > FuncParams.length)) {
1063           
1064             return false;
1065         } else {
1066             
1067             bool result = true;
1068             foreach (index, Argument; ArgTuple) {
1069           
1070                 static if (!is(Argument : RuntimeReference) && !isImplicitlyConvertible!(Argument, FuncParams[index])) {
1071           
1072                     result = false;
1073                     break;
1074                 } 
1075             }
1076             
1077             return result;
1078         }
1079     }
1080 }
1081 	
1082 mixin template assertFieldCompatible(T, string field, Arg) {
1083     import aermicioi.util.traits;
1084     import std.traits;
1085     import std.meta;
1086     
1087     static assert(isField!(T, field), name!T ~ "'s " ~ field ~ " member is not a field");
1088     static assert(isProtection!(T, field, "public"), name!T ~ "'s " ~ field ~ " is not public and therefore cannot be accessed.");
1089     static assert(is(Arg : RuntimeReference) ? true : isImplicitlyConvertible!(Arg, typeof(getMember!(T, field))), name!T ~"'s " ~ field ~ " type " ~ name!(typeof(getMember!(T, field))) ~ " doesn't match with passed arguments type " ~ name!Arg);
1090 }
1091 
1092 enum bool isFieldCompatible(T, string field, Arg) = 
1093     isField!(T, field) &&
1094     isProtection!(T, field, "public") &&
1095     is(Arg : RuntimeReference) ? true : isImplicitlyConvertible!(Arg, typeof(getMember!(T, field)));
1096 
1097 mixin template assertObjectConstructorCompatible(T, Args...) {
1098     import aermicioi.util.traits;
1099     import std.traits;
1100     import std.meta;
1101     
1102     static assert(hasMember!(T, "__ctor"), name!T ~ " doesn't have any constructor to call.");
1103     static assert(isProtection!(T, "__ctor", "public"), name!T ~ "'s constructor is not public.");
1104     static assert(isSomeFunction!(__traits(getMember, T, "__ctor")), name!T ~ "'s constructor is not a function, probably a template.");
1105     static assert(variadicFunctionStyle!(__traits(getMember, T, "__ctor")) == Variadic.no, name!T ~ "'s constructor is a variadic function. Only non-variadic constructors are supported.");
1106     static assert(Filter!(partialSuffixed!(isArgumentListCompatible, Args), __traits(getOverloads, T, "__ctor")).length == 1, "None, or multiple overloads found for " ~ name!T ~ "'s constructor with passed arguments.");
1107 }
1108 
1109 enum bool isObjectConstructorCompatible(T, Args...) = isMethodCompatible!(T, "__ctor", Args);
1110 
1111 mixin template assertObjectMethodCompatible(T, string method, Args...) {
1112     import std.range : only;
1113     import std.array : array;
1114     import aermicioi.util.traits;
1115     import std.traits;
1116     import std.meta;
1117     
1118     static assert(hasMember!(T, method), name!T ~ "'s method " ~ method ~ " not found.");
1119     static assert(isProtection!(T, method, "public"), name!T ~ "'s method " ~ method ~ " is not public");
1120     static assert(isSomeFunction!(__traits(getMember, T, method)), name!T ~ "'s member " ~ method ~ " is not a function, probably a field, or a template.");
1121     static assert(variadicFunctionStyle!(__traits(getMember, T, method)) == Variadic.no, name!T ~ "'s method " ~ method ~ "is variadic function. Only non-variadic methods are supported.");
1122     static assert(Filter!(partialSuffixed!(isArgumentListCompatible, Args), getOverloads!(T, method)).length == 1, name!T ~ "'s " ~ method ~ " doesn't have overload matching passed arguments (" ~ only(staticMap!(name, Args)).joiner(", ").array ~ "), or has several overloads that match.");
1123 }
1124 
1125 enum bool isObjectMethodCompatible(T, string method, Args...) = isMethodCompatible!(T, method, Args);
1126 
1127 
1128 template isMethodCompatible(T, string method, Args...) {
1129     enum bool isMethodCompatible = 
1130             hasMember!(T, method) &&
1131             isProtection!(T, method, "public") &&
1132             isSomeFunction!(__traits(getMember, T, method)) &&
1133             (variadicFunctionStyle!(__traits(getMember, T, method)) == Variadic.no) &&
1134             (Filter!(partialSuffixed!(isArgumentListCompatible, Args), getOverloads!(T, method)).length == 1);
1135 }
1136 
1137 template getCompatibleOverload(T, string method, Args...)
1138     if (isObjectMethodCompatible!(T, method, Args)) {
1139     
1140     alias getCompatibleOverload = Filter!(partialSuffixed!(isArgumentListCompatible, Args), getOverloads!(T, method))[0];
1141 }
1142 
1143 alias isStaticMethodCompatible = templateAnd!(
1144     isMethodCompatible, 
1145     chain!(
1146         isStaticFunction, 
1147         getCompatibleOverload
1148     )
1149 );
1150 
1151 alias isNonStaticMethodCompatible = templateAnd!(
1152     isMethodCompatible, 
1153     chain!(
1154         templateNot!isStaticFunction, 
1155         getCompatibleOverload
1156     )
1157 );
1158 
1159 alias isNonStaticMethodCompatibleAndReturnTypeOf(X) = templateAnd!(
1160     isMethodCompatible, 
1161     chain!(
1162         templateNot!isStaticFunction, 
1163         getCompatibleOverload
1164     ),
1165     partialSuffixed!(
1166         chain!(
1167             partialPrefixed!(
1168                 get,
1169                 0
1170             ),
1171             getCompatibleOverload
1172         ),
1173         X
1174     )
1175 );
1176 
1177 private {
1178     template isValueOfType(alias value, Type) {
1179         enum bool isValueOfType = is(typeof(value) == Type);
1180     }
1181     
1182     template isValueOfType(Value, Type) {
1183         enum bool isValueOfType = is(Value == Type);
1184     }
1185     
1186     enum bool isStruct(T) = is(T == struct);
1187     
1188     alias hasDefaultCtor = 
1189         partialSuffixed!(
1190             templateOr!(
1191                 templateNot!hasMember,
1192                 chain!(
1193                     isStruct,
1194                     get!0
1195                 ),
1196                 templateAnd!(
1197                     partialSuffixed!(
1198                         isProtection,
1199                         "public"
1200                     ),
1201                     chain!(
1202                         partialPrefixed!(
1203                             anySatisfy,
1204                             eq!0
1205                         ),
1206                         partialPrefixed!(
1207                             staticMap,
1208                             arity
1209                         ),
1210                         chain!(
1211                             partialPrefixed!(
1212                                 Filter,
1213                                 partialSuffixed!(
1214                                     isProtection,
1215                                     "public"
1216                                 )
1217                             ),
1218                             getOverloads
1219                         )
1220                     )
1221                 )
1222             ),
1223             "__ctor"
1224         );
1225 }