1 /**
2 This module implements annotation based configuration of containers.
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 	Alexandru Ermicioi
31 **/
32 module aermicioi.aedi.configurer.annotation.annotation;
33 
34 public import aermicioi.aedi.factory.reference : lref, anonymous;
35 
36 import aermicioi.aedi.storage.locator;
37 import aermicioi.aedi.storage.allocator_aware;
38 import aermicioi.aedi.storage.storage;
39 import aermicioi.aedi.storage.wrapper;
40 import aermicioi.aedi.container.container;
41 import aermicioi.aedi.factory.factory;
42 import aermicioi.aedi.factory.reference;
43 import aermicioi.aedi.factory.generic_factory;
44 import aermicioi.aedi.factory.proxy_factory;
45 import aermicioi.aedi.exception;
46 import aermicioi.aedi.util.traits;
47 
48 import std.traits;
49 import std.meta;
50 import std.conv : to;
51 import std.algorithm;
52 import std.experimental.allocator;
53 import std.experimental.allocator.gc_allocator;
54 import std.experimental.allocator.mmap_allocator;
55 import std.experimental.allocator.mallocator;
56 
57 @safe:
58 
59 /**
60 Check if T is instance of ComponentAnnotation
61 **/
62 enum bool isComponentAnnotation(T) = is(T : ComponentAnnotation);
63 
64 /**
65 ditto
66 **/
67 enum bool isComponentAnnotation(alias T) = isComponentAnnotation!(toType!T);
68 
69 /**
70 Annotation used to denote a component that should be stored into an container.
71 **/
72 struct ComponentAnnotation {
73 
74 }
75 
76 /**
77 ditto
78 **/
79 alias component = ComponentAnnotation;
80 
81 /**
82 Check if T is instance of ValueAnnotation
83 **/
84 enum bool isValueAnnotation(T) = is(T : ValueAnnotation!Value, Value);
85 
86 /**
87 ditto
88 **/
89 enum bool isValueAnnotation(alias T) = isValueAnnotation!(toType!T);
90 
91 /**
92 Construct the instance using value provided in annotation
93 
94 Params:
95     value = value that should be component created with
96 
97 **/
98 struct ValueAnnotation(Value) {
99 
100     /**
101     value = value that should be component created with
102     **/
103     Value value;
104 }
105 
106 /**
107 ditto
108 **/
109 ValueAnnotation!T value(T)(T value) {
110     return ValueAnnotation!T(value);
111 }
112 
113 /**
114 Check if T is instance of AllocatorAnnotation
115 **/
116 enum bool isAllocatorAnnotation(T) = is(T : AllocatorAnnotation!X, X);
117 
118 /**
119 ditto
120 **/
121 enum bool isAllocatorAnnotation(alias T) = isAllocatorAnnotation!(toType!T);
122 
123 /**
124 Use allocator to allocate component.
125 
126 Params:
127     allocator = allocator used to allocate the component
128 **/
129 struct AllocatorAnnotation(T = RCIAllocator)
130     if (!hasStaticMember!(T, "instance")) {
131 
132     /**
133     Allocator to use for component allocation.
134     **/
135     T allocator;
136 
137     /**
138     Get iallocator
139 
140     Returns:
141         RCIAllocator
142     **/
143     RCIAllocator iallocator() {
144         return this.allocator.allocatorObject;
145     }
146 }
147 
148 /**
149 ditto
150 **/
151 struct AllocatorAnnotation(T)
152     if (hasStaticMember!(T, "instance")) {
153 
154     /**
155     Allocator to use for component allocation.
156     **/
157     T allocator;
158 
159     /**
160     Get iallocator
161 
162     Returns:
163         RCIAllocator
164     **/
165     RCIAllocator iallocator() @trusted {
166         return T.instance.allocatorObject;
167     }
168 }
169 
170 /**
171 ditto
172 **/
173 AllocatorAnnotation!T allocator(T)(T allocator) {
174     return AllocatorAnnotation!T(allocator);
175 }
176 
177 /**
178 ditto
179 **/
180 AllocatorAnnotation!T allocator(T : GCAllocator)() {
181     return AllocatorAnnotation!T();
182 }
183 
184 /**
185 ditto
186 **/
187 AllocatorAnnotation!T allocator(T : MmapAllocator)() {
188     return AllocatorAnnotation!T();
189 }
190 
191 /**
192 ditto
193 **/
194 AllocatorAnnotation!T allocator(T : Mallocator)() {
195     return AllocatorAnnotation!T();
196 }
197 
198 /**
199 Check if T is instance of ConstructorAnnotation
200 **/
201 enum bool isConstructorAnnotation(T) = is(T : ConstructorAnnotation!Z, Z...);
202 
203 /**
204 ditto
205 **/
206 enum bool isConstructorAnnotation(alias T) = isConstructorAnnotation!(toType!T);
207 /**
208 Annotation used to mark a constructor to be used for component instantiation.
209 
210 Params:
211     Args = tuple of argument types for arguments to be passed into a constructor.
212 **/
213 struct ConstructorAnnotation(Args...) {
214 
215     /**
216     List of arguments for constructor
217     **/
218     Args args;
219 
220     /**
221     Constructor accepting a list of arguments, that will be passed to constructor.
222 
223     Params:
224     	args = arguments passed to component's constructor
225     **/
226     this(Args args) {
227         this.args = args;
228     }
229 }
230 
231 /**
232 ditto
233 **/
234 auto constructor(Args...)(Args args) {
235     return ConstructorAnnotation!Args(args);
236 }
237 
238 /**
239 Check if T is instance of SetterAnnotation
240 **/
241 enum bool isSetterAnnotation(T) = is(T : SetterAnnotation!Z, Z...);
242 
243 /**
244 ditto
245 **/
246 enum bool isSetterAnnotation(alias T) = isSetterAnnotation!(toType!T);
247 /**
248 Annotation used to mark a member to be called or set (in case of fields), with args passed to setter.
249 
250 Note: if an overloaded method is annotated with Setter, the method from overload set that matches argument list in Setter annotation
251 will be called.
252 
253 Params:
254     Args = the argument types of arguments passed to method
255 **/
256 struct SetterAnnotation(Args...) {
257 
258     /**
259     Arguments passed to method
260     **/
261     Args args;
262 
263     /**
264     Constructor accepting a list of arguments, that will be passed to method, or set to a field.
265 
266     Params:
267     	args = arguments passed to component's constructor
268     **/
269     this(Args args) {
270         this.args = args;
271     }
272 }
273 
274 /**
275 ditto
276 **/
277 auto setter(Args...)(Args args) {
278     return SetterAnnotation!Args(args);
279 }
280 
281 /**
282 Check if T is instance of CallbackFactoryAnnotation
283 **/
284 enum bool isCallbackFactoryAnnotation(T) = is(T : CallbackFactoryAnnotation!Z, Z...);
285 
286 /**
287 ditto
288 **/
289 enum bool isCallbackFactoryAnnotation(alias T) = isCallbackFactoryAnnotation!(toType!T);
290 /**
291 Annotation that specifies a delegate to be used to instantiate component.
292 
293 Params:
294 	Z = the type of component that will be returned by the delegate
295 	Args = type tuple of args that can be passed to delegate.
296 **/
297 struct CallbackFactoryAnnotation(Z, Dg, Args...)
298     if ((is(Dg == Z delegate (RCIAllocator, Locator!(), Args)) || is(Dg == Z function (RCIAllocator, Locator!(), Args)))) {
299 
300     /**
301 	Arguments that can be passed to delegate.
302     **/
303     Args args;
304 
305     /**
306     Delegate that is used to create component
307     **/
308     Dg dg;
309 
310     /**
311     Constructor accepting a factory delegate, and it's arguments.
312 
313     Params:
314     	dg = delegate that will factory a component
315     	args = list of arguments passed to delegate.
316     **/
317     this(Dg dg, ref Args args) {
318         this.dg = dg;
319         this.args = args;
320     }
321 }
322 
323 /**
324 ditto
325 **/
326 auto fact(T, Args...)(T delegate(RCIAllocator, Locator!(), Args) dg, Args args) {
327     return CallbackFactoryAnnotation!(T, T delegate(RCIAllocator, Locator!(), Args), Args)(dg, args);
328 }
329 
330 /**
331 ditto
332 **/
333 auto fact(T, Args...)(T function(RCIAllocator, Locator!(), Args) dg, Args args) {
334     return CallbackFactoryAnnotation!(T, T function(RCIAllocator, Locator!(), Args), Args)(dg, args);
335 }
336 
337 /**
338 Check if T is instance of CallbackConfigurerAnnotation
339 **/
340 enum bool isCallbackConfigurerAnnotation(T) = is(T : CallbackConfigurerAnnotation!Z, Z...);
341 
342 /**
343 ditto
344 **/
345 enum bool isCallbackConfigurerAnnotation(alias T) = isCallbackConfigurerAnnotation!(toType!T);
346 /**
347 Annotation that specifies a delegate to be used to configure component somehow.
348 
349 Params:
350 	Z = the type of component that will be returned by the delegate
351 	Args = type tuple of args that can be passed to delegate.
352 **/
353 struct CallbackConfigurerAnnotation(Z, Dg, Args...)
354     if (
355         is(Dg == void delegate (Locator!(), Z, Args)) ||
356         is(Dg == void function (Locator!(), Z, Args)) ||
357         is(Dg == void delegate (Locator!(), ref Z, Args)) ||
358         is(Dg == void function (Locator!(), ref Z, Args))
359     ){
360 
361     /**
362     Args that can be passed to delegate
363     **/
364     Args args;
365 
366     /**
367     Delegate that is used to configure component
368     **/
369     Dg dg;
370 
371     /**
372     Constructor accepting a configurer delegate, and it's arguments.
373 
374     Params:
375     	dg = delegate that will be used to configure a component
376     	args = list of arguments passed to delegate.
377     **/
378     this(Dg dg, ref Args args) {
379         this.dg = dg;
380         this.args = args;
381     }
382 }
383 
384 /**
385 ditto
386 **/
387 auto callback(T, Args...)(void delegate (Locator!(), ref T, Args) dg, Args args) {
388     return CallbackConfigurerAnnotation!(T, void delegate (Locator!(), ref T, Args), Args)(dg, args);
389 }
390 
391 /**
392 ditto
393 **/
394 auto callback(T, Args...)(void function (Locator!(), ref T, Args) dg, Args args) {
395     return CallbackConfigurerAnnotation!(T, void function (Locator!(), ref T, Args), Args)(dg, args);
396 }
397 
398 /**
399 ditto
400 **/
401 auto callback(T, Args...)(void delegate (Locator!(), T, Args) dg, Args args) {
402     return CallbackConfigurerAnnotation!(T, void delegate (Locator!(), T, Args), Args)(dg, args);
403 }
404 
405 /**
406 ditto
407 **/
408 auto callback(T, Args...)(void function (Locator!(), T, Args) dg, Args args) {
409     return CallbackConfigurerAnnotation!(T, void function (Locator!(), T, Args), Args)(dg, args);
410 }
411 
412 /**
413 Check if T is instance of AutowiredAnnotation
414 **/
415 enum bool isAutowiredAnnotation(T) = is(T : AutowiredAnnotation);
416 
417 /**
418 ditto
419 **/
420 enum bool isAutowiredAnnotation(alias T) = isAutowiredAnnotation!(toType!T);
421 
422 /**
423 Annotation used to mark constructor or method for auto wiring.
424 
425 Marking a method/constructor with autowired annotation will make container to call it with arguments fetched from
426 locator by types of them.
427 
428 Note: even if a method/constructor from an overloaded set is marked with autowired annotation, the first method from overload set
429 will be used. Due to that autowired annotation is recommended to use on methods/constrcutors that are not overloaded.
430 
431 **/
432 struct AutowiredAnnotation {
433 
434 }
435 
436 /**
437 ditto
438 **/
439 alias autowired = AutowiredAnnotation;
440 
441 /**
442 Check if T is instance of QualifierAnnotation
443 **/
444 enum bool isQualifierAnnotation(T) = is(T : QualifierAnnotation);
445 
446 /**
447 ditto
448 **/
449 enum bool isQualifierAnnotation(alias T) = isQualifierAnnotation!(toType!T);
450 
451 /**
452 An annotation used to provide custom identity for an object in container.
453 **/
454 struct QualifierAnnotation {
455     /**
456     Identity of component
457     **/
458     string id;
459 }
460 
461 /**
462 An annotation used to provide custom identity for an object in container.
463 
464 This function is a convenince function to automatically infer required types for underlying annotation.
465 
466 Params:
467     id = identity of object in container
468 **/
469 QualifierAnnotation qualifier(string id) {
470     return QualifierAnnotation(id);
471 }
472 
473 /**
474 ditto
475 **/
476 QualifierAnnotation qualifier(string id)() {
477     return QualifierAnnotation(id);
478 }
479 
480 /**
481 An annotation used to provide custom identity for an object in container by some interface.
482 
483 This function is a convenince function to automatically infer required types for underlying annotation.
484 
485 Params:
486     I = identity of object in container
487 **/
488 QualifierAnnotation qualifier(I)() {
489     return QualifierAnnotation(name!I);
490 }
491 
492 /**
493 Check if T is instance of ContainedAnnotation
494 **/
495 enum bool isContainedAnnotation(T) = is(T : ContainedAnnotation);
496 
497 /**
498 ditto
499 **/
500 enum bool isContainedAnnotation(alias T) = isContainedAnnotation!(toType!T);
501 /**
502 When objects are registered into a component container, this annotation marks in which sub-container it is required to store.
503 **/
504 struct ContainedAnnotation {
505     /**
506     The id of container which will manage component.
507     **/
508     string id;
509 }
510 
511 /**
512 When objects are registered into a component container, this annotation marks in which sub-container it is required to store.
513 
514 This function is a convenince function to automatically infer required types for underlying annotation.
515 
516 Params:
517     id = identity of container where to store the object.
518 **/
519 ContainedAnnotation contained(string id) {
520     return ContainedAnnotation(id);
521 }
522 
523 /**
524 Check if T is instance of CallbackDestructor
525 **/
526 enum bool isCallbackDestructor(T) = is(T) && is(T == DefaultDestructor);
527 
528 /**
529 ditto
530 **/
531 enum bool isCallbackDestructor(alias T) = is(typeof(T));
532 
533 /**
534 Use callback stored in annotation to destroy a component of type T
535 
536 Params:
537     dg = callback used to destroy the component
538     args = arguments passed to callback to destroy the component
539 **/
540 struct CallbackDestructor(T, Dg : void delegate(RCIAllocator, ref T destructable, Args), Args...) {
541     /**
542     Callback used to destroy the component
543     **/
544     Dg dg;
545 
546     /**
547     Arguments passed to callback to destroy the component
548     **/
549     Args args;
550 }
551 
552 /**
553 ditto
554 **/
555 CallbackDestructor callbackDestructor(T, Dg : void delegate(RCIAllocator, ref T destructable, Args), Args...)(Dg dg, Args args) {
556     return CallbackDestructor(dg, args);
557 }
558 
559 /**
560 Check if T is instance of DestructorMethod
561 **/
562 enum bool isDestructorMethod(T) = is(T) && is(T == DefaultDestructor);
563 
564 /**
565 ditto
566 **/
567 enum bool isDestructorMethod(alias T) = is(typeof(T));
568 
569 /**
570 Use method from instance of type T to destroy a component of type Z
571 
572 Params:
573     method = method used to destroy component of type Z
574     args = list of arguments to pass to destructor method
575 **/
576 struct DestructorMethod(string method, T, Z, Args...) {
577 
578     /**
579     List of arguments to pass to destructor method
580     **/
581     Args args;
582 }
583 
584 /**
585 ditto
586 **/
587 CallbackDestructor destructorMethod(string method, T, Z, Args...)() {
588     return DestructorMethod(dg, args);
589 }