1 /**
2 License:
3 	Boost Software License - Version 1.0 - August 17th, 2003
4 
5 	Permission is hereby granted, free of charge, to any person or organization
6 	obtaining a copy of the software and accompanying documentation covered by
7 	this license (the "Software") to use, reproduce, display, distribute,
8 	execute, and transmit the Software, and to prepare derivative works of the
9 	Software, and to permit third-parties to whom the Software is furnished to
10 	do so, all subject to the following:
11 
12 	The copyright notices in the Software and this entire statement, including
13 	the above license grant, this restriction and the following disclaimer,
14 	must be included in all copies of the Software, in whole or in part, and
15 	all derivative works of the Software, unless such copies or derivative
16 	works are solely in the form of machine-executable object code generated by
17 	a source language processor.
18 
19 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
22 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
23 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
24 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
25 	DEALINGS IN THE SOFTWARE.
26 
27 Authors:
28 	aermicioi
29 **/
30 module aermicioi.aedi.configurer.register.container;
31 
32 import aermicioi.aedi.container;
33 import std.traits;
34 import std.meta;
35 import aermicioi.aedi.util.traits;
36 
37 @safe:
38 
39 /**
40 Create a singleton container
41 
42 Returns:
43 	SingletonContainer
44 **/
45 auto singleton() {
46     return new SingletonContainer();
47 }
48 
49 /**
50 Create a prototype container
51 
52 Returns:
53 	PrototypeContainer
54 **/
55 auto prototype() {
56     return new PrototypeContainer();
57 }
58 
59 /**
60 Create a container for values
61 
62 Returns:
63 	ValueContainer
64 **/
65 auto values() {
66     return new ValueContainer();
67 }
68 
69 /**
70 Wrap up a container into switchable container.
71 
72 Wraps up a container to provide switching capabilites to it.
73 
74 Params:
75 	container = container to wrap up in switchable container
76 
77 Returns:
78 	SwitchableContainer!T
79 **/
80 auto switchable(T : Container)(auto ref T container) {
81     return (new SwitchableContainer!T()).decorated(container);
82 }
83 
84 /**
85 Wrap up a container into subscribable container.
86 
87 Wraps up a container to provide events to subscribe to.
88 
89 Params:
90 	container = container to wrap up in subscribable container
91 
92 Returns:
93 	SubscribableContainer!T
94 **/
95 auto subscribable(T : Container)(auto ref T container) {
96     return (new SubscribableContainer!T()).decorated(container);
97 }
98 
99 /**
100 Wrap up a container into a type based container.
101 
102 Wraps up container into a container that adds capability to
103 search for a component based on it's type, or implemented
104 hierarchy of classes and interfaces.
105 
106 Params:
107 	container = container to wrap up in typed container
108 
109 Returns:
110 	TypeBasedContainer!T
111 **/
112 auto typed(T : Container)(auto ref T container) {
113     return (new TypeBasedContainer!T()).decorated(container);
114 }
115 
116 /**
117 Wrap up a container into aliasing container.
118 
119 Wraps up container into aliasing container which provides
120 capabilities to alias identity of components in original container.
121 
122 Params:
123 	container = container to wrap up in aliasing container
124 
125 Returns:
126 	AliasingContainer!T
127 **/
128 auto aliasing(T)(auto ref T container) {
129     return (new AliasingContainer!T()).decorated(container);
130 }
131 
132 /**
133 Wrap up a container into a deferring container.
134 
135 Wraps up container into a deferring container which executes deferred actions
136 when a component from it is requested from exterior and not interior of container.
137 Therefore with help of it, is possible to solve circular dependency errors by deferring
138 setting a dependency at a later time when dependents are fully constructed.
139 
140 Params:
141 	container = container to wrap up in defferred container
142 	deferredExecutionerIdentity = identity of container for defferred actions that will be used by contained factories if needed.
143 
144 Returns:
145 	DefferedContainer!T
146 **/
147 auto deferred(T)(auto ref T container, string deferredExecutionerIdentity) {
148 	return (new DeferredContainer!T(container, deferredExecutionerIdentity));
149 }
150 
151 /**
152 ditto
153 **/
154 auto deferred(T)(auto ref T container) {
155 	return (new DeferredContainer!T(container));
156 }
157 
158 /**
159 Wrap up container into gc registering container.
160 
161 Wrap up container into gc registering container, that will automatically
162 register all created components by it into garbage collector for proper
163 scanning.
164 
165 Params:
166 	container = container to decorate with gc component registration.
167 
168 Returns:
169 	GcRegisteringContainer!T
170 **/
171 auto gcRegistered(T)(auto ref T container) {
172 	return (new GcRegisteringContainer!T).decorated(container);
173 }
174 
175 /**
176 Wraps up several containers into one.
177 
178 Params:
179 	containers = a list of containers to be used together
180 
181 Returns:
182 	TupleContainer!T
183 **/
184 auto container(T...)(T containers)
185     if (allSatisfy!(partialSuffixed!(isDerived, Container), T)) {
186     return new TupleContainer!T(containers);
187 }
188 
189 /**
190 Wraps up several containers into one.
191 
192 Params:
193 	managed = first container managed by aggregate one
194 	identity = identity of container by which it is possible to identify it
195 	manageds = a set of containers in pairs of (managed, identity)
196 
197 Returns:
198 	TupleContainer!T
199 **/
200 auto aggregate(T...)(Container managed, string identity, T manageds) {
201 	AggregateContainer container = new AggregateContainer;
202 
203 	return container.aggregate(managed, identity, manageds);
204 }
205 
206 /**
207 Wrap up container into describing container.
208 
209 Wrap up container into describing container, that
210 provides description of itself and underlying components
211 through a set of Describer components.
212 
213 Params:
214 	componentDescriber = describer for components container manages
215 	fallbackComponentDescriber = fallback describer in case componentDescriber fails to describe particular component
216 	containerDescriber = describer used to describe container itself
217 
218 Returns:
219 	DescribingContainer!T
220 **/
221 auto describing(T : Container)(T container, Describer!() componentDescriber, Describer!() containerDescriber, Describer!() fallbackComponentDescriber) {
222 	return new DescribingContainer!T(container, componentDescriber, containerDescriber, fallbackComponentDescriber);
223 }
224 
225 /**
226 ditto
227 **/
228 auto describing(T : Container)(T container, Describer!() componentDescriber, Describer!() containerDescriber) {
229 	return new DescribingContainer!T(container, componentDescriber, containerDescriber);
230 }
231 
232 /**
233 ditto
234 **/
235 auto describing(T : Container)(T container, Describer!() componentDescriber, string title, string description) {
236 	return new DescribingContainer!T(container, componentDescriber, new StaticDescriber!()(typeid(T).toString, title, description));
237 }
238 
239 /**
240 ditto
241 **/
242 auto describing(T : Container)(T container, string title = null, string description = null) {
243 	return new DescribingContainer!T(container, new IdentityDescriber!(), new StaticDescriber!()(typeid(T).toString, title, description));
244 }
245 
246 /**
247 A prebuilt container with all features enabled.
248 
249 Params:
250 	title = container title.
251 	description = container description.
252 
253 Returns:
254 	Prebuild container from singleton, prototype, and values containers.
255 **/
256 auto application(string title, string description) {
257 	return aggregate(
258 		singleton.typed, "singleton",
259 		prototype.typed, "prototype",
260 		values, "parameters"
261 	)
262 	.aliasing
263 	.gcRegistered
264 	.deferred
265 	.describing(title, description)
266 	.subscribable;
267 }
268 
269 private {
270 
271 	auto aggregate(T...)(AggregateContainer container, Container managed, string identity, T manageds) {
272 		container.set(managed, identity);
273 
274 		static if (T.length > 1) {
275 			container.aggregate(manageds);
276 		}
277 		return container;
278 	}
279 }