1 module aermicioi.aedi.container.deferred_container;
2 
3 import aermicioi.aedi.container.container;
4 import aermicioi.aedi.storage.decorator;
5 import aermicioi.aedi.storage.alias_aware;
6 import aermicioi.aedi.factory.deferring_factory;
7 import aermicioi.aedi.factory.factory;
8 import aermicioi.aedi.storage.storage;
9 import aermicioi.aedi.storage.locator;
10 import aermicioi.aedi.factory.reference : RuntimeReference, resolve;
11 
12 import std.meta;
13 import std.traits;
14 import aermicioi.aedi.util.traits;
15 
16 /**
17 Decorating container that executes deffered tasks after a request is served from exterior.
18 This decorated will inherit following interfaces only and only if the
19 T also implements them:
20   $(OL
21       $(LI Storage!(ObjectFactory, string))
22       $(LI AliasAware!string)
23       $(LI FactoryLocator)
24   )
25 Decorated container must implement following interfaces:
26     $(OL
27         $(LI Container)
28         $(LI MutableDecorator!T)
29         $(LI Subscribable!ContainerInstantiationEventType)
30         $(LI Decorator!Container)
31     )
32 
33 Params:
34     T = The decorated that switchable decorated will decorate.
35 **/
36 template DeferredContainer(T)
37 {
38 
39     /**
40     Set which the switchable container will decorate for T. By default
41     Locator!() and Subscribable!ContainerInstantiationEventType is included.
42     **/
43     alias InheritanceSet = NoDuplicates!(Filter!(
44         templateOr!(
45             partialSuffixed!(
46                 isDerived,
47                 Storage!(ObjectFactory, string)
48             ),
49             partialSuffixed!(
50                 isDerived,
51                 AliasAware!string
52             ),
53             partialSuffixed!(
54                 isDerived,
55                 FactoryLocator!ObjectFactory
56             )
57         ),
58         InterfacesTuple!T),
59         Container,
60         Decorator!Container
61     );
62 
63     @safe class DeferredContainer : InheritanceSet
64     {
65         private
66         {
67             DeferralContext context;
68             const string contextIdentity;
69         }
70 
71         public
72         {
73 
74             /**
75             Default constructor for DefferedContainer
76             **/
77             this(T container)
78             {
79                 this.decorated = container;
80                 context = new DeferralContext();
81                 contextIdentity = typeid(DeferralContext).toString();
82             }
83 
84             this(T container, string contextIdentity) {
85                 this.decorated = container;
86                 context = new DeferralContext();
87                 this.contextIdentity = contextIdentity;
88             }
89 
90             mixin MutableDecoratorMixin!T;
91 
92             static if (is(T : Storage!(Type, Id), Type, Id)) {
93 
94                 mixin StorageMixin!(typeof(this));
95             }
96 
97             static if (is(T : AliasAware!(X), X)) {
98 
99                 mixin AliasAwareMixin!(typeof(this));
100             }
101 
102             static if (is(T : FactoryLocator!(Z), Z)) {
103 
104                 mixin FactoryLocatorMixin!(typeof(this));
105             }
106 
107             /**
108             Get object created by a factory identified by key
109 
110             Params:
111                 key = identity of factory
112             Returns:
113            	Object
114             **/
115             Object get(string key)
116             {
117                 if (key == contextIdentity) {
118                     return context;
119                 }
120 
121                 Object result = this.decorated.get(key);
122 
123                 if (context.pending) {
124                     context.execute;
125                 }
126 
127                 return result;
128             }
129 
130             /**
131             Check if an object factory for it exists in container.
132 
133             Params:
134                 key = identity of factory
135             Returns:
136                 bool
137             **/
138             bool has(in string key) inout
139             {
140                 if (key == this.contextIdentity) {
141                     return true;
142                 }
143 
144                 return this.decorated_.has(key);
145             }
146 
147             mixin ContainerMixin!(typeof(this));
148         }
149     }
150 }