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.factory.wrapping_factory;
31 
32 import aermicioi.aedi.exception.di_exception;
33 import aermicioi.aedi.factory.factory;
34 import aermicioi.aedi.factory.generic_factory;
35 import aermicioi.aedi.storage.decorator;
36 import aermicioi.aedi.storage.allocator_aware;
37 import aermicioi.aedi.storage.locator;
38 import aermicioi.aedi.storage.wrapper;
39 import std.traits;
40 
41 /**
42 Wraps up the result of some factory in Wrapper object if component is not
43 derived from Object.
44 **/
45 @safe class WrappingFactory(T : Factory!Z, Z) : ObjectFactory, MutableDecorator!T {
46 
47     private {
48         RCIAllocator allocator_;
49 
50         T decorated_;
51     }
52 
53     public {
54 
55         /**
56         Constructor for WrappingFactory!(T, Z)
57 
58         Params:
59             factory = factory that is wrapped
60         **/
61         this(T factory) {
62             import std.experimental.allocator : theAllocator;
63 
64             this.decorated = factory;
65             this.allocator = theAllocator;
66         }
67 
68         @property {
69             /**
70             Set allocator
71 
72             Params:
73                 allocator = allocator used to allocate wrappers when needed.
74 
75             Returns:
76                 typeof(this)
77             **/
78             typeof(this) allocator(RCIAllocator allocator) @safe nothrow
79             in (allocator !is null, "Expected an allocator, not null.") {
80                 this.allocator_ = allocator;
81                 this.decorated.allocator = allocator;
82 
83                 return this;
84             }
85 
86             /**
87             Get allocator
88 
89             Returns:
90                 RCIAllocator
91             **/
92             RCIAllocator allocator() @safe nothrow {
93                 return this.allocator_;
94             }
95             /**
96             Set the decorated object for decorator.
97 
98             Params:
99                 decorated = decorated component
100 
101             Returns:
102             	this
103             **/
104         	WrappingFactory!(T, Z) decorated(T decorated) @safe nothrow pure
105             in (decorated !is null, "Expected a factory to decorate for type " ~ typeid(T).toString ~ " not null.") {
106         		this.decorated_ = decorated;
107 
108         		return this;
109         	}
110 
111             /**
112             Get the decorated object.
113 
114             Returns:
115             	T decorated object
116             **/
117         	inout(T) decorated() @safe nothrow inout {
118         		return this.decorated_;
119         	}
120 
121             /**
122     		Get the type info of T that is created.
123 
124     		Returns:
125     			TypeInfo object of created component.
126     		**/
127         	TypeInfo type() @safe nothrow const {
128         	    return this.decorated.type;
129         	}
130 
131             /**
132             Set a locator to object.
133 
134             Params:
135                 locator = the locator that is set to oject.
136 
137             Returns:
138                 LocatorAware.
139             **/
140         	WrappingFactory!T locator(Locator!() locator) {
141         		this.decorated.locator = locator;
142 
143         		return this;
144         	}
145 
146         }
147 
148         /**
149 		Instantiates component of type T.
150 
151 		Returns:
152 			Object instantiated component and probably wrapped if not derived from Object.
153 		**/
154         Object factory() @trusted {
155             static if (is(Z : Object)) {
156 
157                 return this.decorated.factory;
158             } else static if (is(Z == class)) {
159                 import aermicioi.aedi.storage.wrapper : CastableWrapperImpl;
160                 return this.allocator.make!(CastableWrapperImpl!(Z, InterfacesTuple!Z))(this.decorated.factory);
161                 // return this.allocator.make!(CastableWrapperImpl!(Z, InterfacesTuple!Z, BaseClassesTuple!Z))(this.decorated.factory); /// Nope not working with extern classes
162             } else static if (is(Z == ubyte)) {
163                 return this.allocator.make!(CastableWrapperImpl!(Z, ushort, uint, ulong, short, int, long, float, double))(this.decorated.factory);
164             } else static if (is(Z == ushort)) {
165                 return this.allocator.make!(CastableWrapperImpl!(Z, uint, ulong, int, long, float, double))(this.decorated.factory);
166             } else static if (is(Z == uint)) {
167                 return this.allocator.make!(CastableWrapperImpl!(Z, ulong, long, float, double))(this.decorated.factory);
168             } else static if (is(Z == ulong)) {
169                 return this.allocator.make!(CastableWrapperImpl!(Z, double))(this.decorated.factory);
170             } else static if (is(Z == byte)) {
171                 return this.allocator.make!(CastableWrapperImpl!(Z, short, int, long, float, double))(this.decorated.factory);
172             } else static if (is(Z == short)) {
173                 return this.allocator.make!(CastableWrapperImpl!(Z, int, long, float, double))(this.decorated.factory);
174             } else static if (is(Z == int)) {
175                 return this.allocator.make!(CastableWrapperImpl!(Z, long, float, double))(this.decorated.factory);
176             } else static if (is(Z == long)) {
177                 return this.allocator.make!(CastableWrapperImpl!(Z, double))(this.decorated.factory);
178             } else static if (is(Z == float)) {
179                 return this.allocator.make!(CastableWrapperImpl!(Z, double))(this.decorated.factory);
180             } else static if (is(Z == double)) {
181                 return this.allocator.make!(WrapperImpl!(Z))(this.decorated.factory);
182             } else {
183                 return this.allocator.make!(WrapperImpl!Z)(this.decorated.factory);
184             }
185         }
186 
187         /**
188         Destructs a component of type T.
189 
190         Params:
191             component = component that is to ve destroyed.
192 
193         Returns:
194 
195         **/
196         void destruct(ref Object component) @trusted {
197             static if (is(Z : Object)) {
198 
199                 Z casted = cast(Z) component;
200 
201                 if (casted !is null) {
202 
203                     this.decorated.destruct(casted);
204                     return;
205                 }
206             } else {
207 
208                 Wrapper!Z casted = cast(Wrapper!Z) component;
209 
210                 if (casted !is null) {
211                     this.decorated.destruct(casted.value);
212                     this.allocator.dispose(component);
213                     return;
214                 }
215             }
216 
217             import aermicioi.aedi.exception.invalid_cast_exception : InvalidCastException;
218             throw new InvalidCastException(
219                 "Cannot destruct component of type ${actual} expected component of ${expected} type", null, typeid(Z), component.classinfo
220             );
221         }
222 
223     }
224 }