1 /**
2 Contains a specific implementation of generic factory used solely in conjunction
3 with register api.
4 
5 License:
6 	Boost Software License - Version 1.0 - August 17th, 2003
7 
8 	Permission is hereby granted, free of charge, to any person or organization
9 	obtaining a copy of the software and accompanying documentation covered by
10 	this license (the "Software") to use, reproduce, display, distribute,
11 	execute, and transmit the Software, and to prepare derivative works of the
12 	Software, and to permit third-parties to whom the Software is furnished to
13 	do so, all subject to the following:
14 
15 	The copyright notices in the Software and this entire statement, including
16 	the above license grant, this restriction and the following disclaimer,
17 	must be included in all copies of the Software, in whole or in part, and
18 	all derivative works of the Software, unless such copies or derivative
19 	works are solely in the form of machine-executable object code generated by
20 	a source language processor.
21 
22 	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
23 	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
24 	FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
25 	SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
26 	FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
27 	ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
28 	DEALINGS IN THE SOFTWARE.
29 
30 Authors:
31 	aermicioi
32 **/
33 module aermicioi.aedi.configurer.register.configuration_context_factory;
34 
35 import aermicioi.aedi.util.typecons : ArgsConstructor;
36 import aermicioi.aedi.factory.decorating_factory;
37 import aermicioi.aedi.factory.factory;
38 import aermicioi.aedi.factory.generic_factory;
39 import aermicioi.aedi.storage.storage;
40 import aermicioi.aedi.storage.decorator : MutableDecoratorMixin;
41 import aermicioi.aedi.storage.locator : Locator;
42 import std.experimental.allocator : RCIAllocator;
43 
44 package
45 {
46 
47 	@safe class ConfigurableFactory(T, Policies...) : GenericFactory!T
48 	{
49 
50 		static foreach (Policy; Policies)
51 		{
52 			mixin Policy!();
53 		}
54 	}
55 
56 	mixin template DecoratingFactoryPolicy()
57 	{
58 		import aermicioi.aedi.storage.allocator_aware : AllocatorAwareMixin;
59 		import aermicioi.aedi.storage.locator_aware : LocatorAwareMixin;
60 		mixin MutableDecoratorMixin!(GenericFactory!T);
61 		mixin InstanceDestructorAwareDecoratorMixin!T;
62 		mixin InstanceFactoryAwareDecoratorMixin!T;
63 		mixin PropertyConfigurersAwareDecoratorMixin!T;
64 
65 		/**
66 		Instantiates component of type T.
67 
68 		Returns:
69 			T instantiated component.
70 		**/
71 		T factory() @safe {
72 			return this.decorated.factory();
73 		}
74 
75 		/**
76 		Destructs a component of type T.
77 
78 		Params:
79 			component = component that is to ve destroyed.
80 		**/
81 		void destruct(ref T component) @safe {
82 			this.decorated.destruct(component);
83 		}
84 
85 		@property {
86 
87 			/**
88 			Get the type info of T that is created.
89 
90 			Returns:
91 				TypeInfo object of created component.
92 			**/
93 			TypeInfo type() @safe nothrow const {
94 				return this.decorated.type();
95 			}
96 		}
97 
98 		// allocator section, required due to more advanced logic that storing.
99 		import std.experimental.allocator : RCIAllocator, make, theAllocator;
100 		private {
101 			RCIAllocator allocator_;
102 		}
103 
104 		public {
105 			@property {
106 				/**
107 				Set allocator
108 
109 				Params:
110 					allocator = allocator used to create components
111 
112 				Returns:
113 					typeof(this)
114 				**/
115 				typeof(this) allocator(RCIAllocator allocator) @safe nothrow
116 				in {
117 					assert(!allocator.isNull, "Expected an allocator, not null.");
118 				}
119 				do {
120 					this.allocator_ = allocator;
121 
122 					if (this.decorated_ !is null) {
123 						this.decorated.allocator = allocator;
124 					}
125 
126 					return this;
127 				}
128 
129 				/**
130 				Get allocator
131 
132 				Returns:
133 					Z
134 				**/
135 				inout(RCIAllocator) allocator() @safe nothrow inout
136 				out(allocator) {
137 					assert(!allocator.isNull, "Expected an allocator, not null.");
138 				}
139 				do {
140 					return this.allocator_;
141 				}
142 			}
143 		}
144 
145 		// Locator storage, same reason as for allocator.
146 		import aermicioi.aedi.storage.locator;
147 		private {
148 			Locator!() locator_;
149 		}
150 
151 		@property {
152 			/**
153 			Set locator
154 
155 			Params:
156 				locator = the locator used somehow by locator aware component
157 
158 			Returns:
159 				typeof(this)
160 			**/
161 			typeof(this) locator(Locator!() locator) @safe nothrow
162 			in (locator !is null, "A locator is expected not null.")
163 			{
164 				this.locator_ = locator;
165 
166 				if (this.decorated_ !is null) {
167 					this.decorated.locator = locator;
168 				}
169 
170 				return this;
171 			}
172 
173 			/**
174 			Get locator
175 
176 			Returns:
177 				Locator!()
178 			**/
179 			inout(Locator!()) locator() @safe nothrow inout
180 			out(lc; lc !is null, "Cannot return a locator, when it wasn't set in first case.") {
181 				return this.locator_;
182 			}
183 		}
184 	}
185 
186 	mixin template RegistrationStorePolicy()
187 	{
188 		private string file_;
189 		private size_t line_;
190 
191 		/**
192 		Set file
193 
194 		Params:
195 			file = location in d module where it was registered
196 		Returns:
197 			typeof(this)
198 		**/
199 		typeof(this) file(string file) @safe nothrow pure
200 		{
201 			this.file_ = file;
202 
203 			return this;
204 		}
205 
206 		/**
207 		Get file
208 
209 		Returns:
210 			string
211 		**/
212 		inout(string) file() @safe nothrow pure inout
213 		{
214 			return this.file_;
215 		}
216 
217 		/**
218 		Set line
219 
220 		Params:
221 			line = line on which registration happened
222 
223 		Returns:
224 			typeof(this)
225 		**/
226 		typeof(this) line(size_t line) @safe nothrow pure
227 		{
228 			this.line_ = line;
229 
230 			return this;
231 		}
232 
233 		/**
234 		Get line
235 
236 		Returns:
237 			size_t
238 		**/
239 		inout(size_t) line() @safe nothrow pure inout
240 		{
241 			return this.line_;
242 		}
243 	}
244 
245 	mixin template WrapperStorePolicy()
246 	{
247 		ObjectFactory wrapper_;
248 
249 		/**
250 		Set wrapper
251 
252 		Params:
253 			wrapper = wrapper of factory stored in storage
254 		Returns:
255 			typeof(this)
256 		**/
257 		typeof(this) wrapper(ObjectFactory wrapper) @safe nothrow pure
258 		{
259 			this.wrapper_ = wrapper;
260 
261 			return this;
262 		}
263 
264 		/**
265 		Get wrapper
266 
267 		Returns:
268 			ObjectFactory
269 		**/
270 		inout(ObjectFactory) wrapper() @safe nothrow pure inout
271 		{
272 			return this.wrapper_;
273 		}
274 	}
275 
276 	mixin template StoragePolicy()
277 	{
278 		Storage!(ObjectFactory, string) storage_;
279 		string identity_;
280 
281 		/**
282 		Set storage
283 
284 		Params:
285 			storage = storage that stores component factories
286 		Returns:
287 			typeof(this)
288 		**/
289 		typeof(this) storage(Storage!(ObjectFactory, string) storage) @safe nothrow pure
290 		{
291 			this.storage_ = storage;
292 
293 			return this;
294 		}
295 
296 		/**
297 		Get storage
298 
299 		Returns:
300 			Storage!(ObjectFactory, string)
301 		**/
302 		inout(Storage!(ObjectFactory, string)) storage() @safe nothrow pure inout
303 		{
304 			return this.storage_;
305 		}
306 
307 		/**
308 		Set identity
309 
310 		Params:
311 			identity = identity of component in storage
312 
313 		Returns:
314 			typeof(this)
315 		**/
316 		typeof(this) identity(string identity) @safe nothrow pure
317 		{
318 			this.identity_ = identity;
319 
320 			return this;
321 		}
322 
323 		/**
324 		Get identity
325 
326 		Returns:
327 			string
328 		**/
329 		inout(string) identity() @safe nothrow pure inout
330 		{
331 			return this.identity_;
332 		}
333 	}
334 
335 	template ContainsPolicy(alias Policy, Policies...) {
336 		import std.traits : fullyQualifiedName;
337 		static foreach (Testable; Policies) {
338 			static if (!is(typeof(Result)) && __traits(isSame, Testable, Policy)) {
339 				enum Result = true;
340 			}
341 		}
342 
343 		static if (!is(typeof(Result))) {
344 			enum Result = false;
345 		}
346 
347 		alias ContainsPolicy = Result;
348 	}
349 }