1 /**
2 Contains factories that are used for decorational purposes like tagging with additional
3  information, or wrapping result of a factory in some container.
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.factory.decorating_factory;
34 
35 import aermicioi.aedi.factory.factory;
36 import aermicioi.aedi.storage.locator;
37 import aermicioi.aedi.factory.generic_factory;
38 import aermicioi.aedi.storage.decorator;
39 
40 alias ObjectFactoryDecorator = Decorator!ObjectFactory;
41 
42 /**
43 Wraps up the result of some factory in Wrapper object if data is not
44 subclass of Object.
45 **/
46 class WrappingFactory(T : Factory!Z, Z) : ObjectFactory, MutableDecorator!T {
47     
48     private {
49         T decorated_;
50     }
51     
52     public {
53         this(T factory) {
54             this.decorated = factory;
55         }
56         
57         @property {
58         	WrappingFactory!(T, Z) decorated(T decorated) @safe nothrow {
59         		this.decorated_ = decorated;
60         	
61         		return this;
62         	}
63         	
64         	T decorated() @safe nothrow {
65         		return this.decorated_;
66         	}
67         	
68         	TypeInfo type() {
69         	    return this.decorated.type;
70         	}
71         	
72         	WrappingFactory!T locator(Locator!() locator) {
73         		this.decorated.locator = locator;
74         	
75         		return this;
76         	}
77         	
78         }
79         
80         Object factory() {
81             static if (is(Z : Object)) {
82                 
83                 return this.decorated.factory;
84             } else {
85                 import aermicioi.aedi.storage.wrapper;
86                 return new Wrapper!Z(this.decorated.factory);
87             }
88         }
89     }
90 }
91 
92 /**
93 A base class for generic factory decorators that channels calls
94 to decorated generic factory.
95 **/
96 abstract class DecoratableGenericFactory(T) : GenericFactory!T, MutableDecorator!(GenericFactory!T) {
97     
98     private {
99         Locator!() locator_;
100         GenericFactory!T decorated_;
101     }
102     
103     public {
104         @property {
105         	
106         	DecoratableGenericFactory!T locator(Locator!() locator) @safe nothrow {
107         		this.locator_ = locator;
108         	
109         		return this;
110         	}
111         	
112         	Locator!() locator() {
113         		return this.locator_;
114         	}
115         	
116         	DecoratableGenericFactory!T decorated(GenericFactory!T decorated) @safe nothrow {
117         		this.decorated_ = decorated;
118         	
119         		return this;
120         	}
121         	
122         	GenericFactory!T decorated() @safe nothrow {
123         		return this.decorated_;
124         	}
125         	
126         	GenericFactory!T setInstanceFactory(InstanceFactory!T factory) {
127         	    this.decorated.setInstanceFactory(factory);
128         	    
129         	    return this;
130         	}
131         }
132         
133         T factory() {
134             return this.decorated.factory();
135         }
136         
137         TypeInfo type() {
138             return this.decorated.type();
139         }
140         
141         GenericFactory!T addPropertyConfigurer(PropertyConfigurer!T configurer) {
142             this.decorated.addPropertyConfigurer(configurer);
143             
144             return this;
145         }
146     }
147 }
148 
149 /**
150 An object that can be tagged with some information.
151 **/
152 interface Taggable(T) {
153     import std.range.interfaces : InputRange;
154     public {
155         
156         /**
157         Tag object with some information
158         
159         Params:
160         	tag = information that object should be tagged with.
161         
162         Returns:
163         	this
164         **/
165         Taggable!T tag(T tag);
166         
167         /**
168         Remove tagged information from object.
169         
170         Params:
171         	tag = tagged information that should be removed
172         
173         Returns:
174         	this
175         **/
176         Taggable!T untag(T tag);
177         
178         /**
179         Get all tagged information from this object.
180         
181         Returns:
182         	T[] a list of tags.
183         **/
184         T[] tags();
185     }
186 }
187 
188 /**
189 Decorates a factory with tagging functionality.
190 **/
191 class TaggableFactoryDecorator(T, Z) : Factory!T, Taggable!Z, Decorator!(Factory!T) {
192     
193     private {
194         Factory!T decorated_;
195         
196         Z[] tags_;
197     }
198     
199     public {
200         @property {
201         	TaggableFactoryDecorator!(T, Z) decorated(Factory!T decorated) @safe nothrow {
202             	this.decorated_ = decorated;
203             
204             	return this;
205             }
206             
207             Factory!T decorated() @safe nothrow {
208             	return this.decorated_;
209             }
210             
211             TaggableFactoryDecorator tags(Z[] tags) @safe nothrow {
212             	this.tags_ = tags;
213             
214             	return this;
215             }
216             
217             Z[] tags() @safe nothrow {
218             	return this.tags_;
219             }
220             
221             TaggableFactoryDecorator locator(Locator!() locator) {
222             	this.decorated.locator = locator;
223             
224             	return this;
225             }
226             
227             TypeInfo type() {
228                 return this.decorated.type;
229             }
230         }
231         
232         TaggableFactoryDecorator tag(Z tag) {
233             this.tags_ ~= tag;
234             
235             return this;
236         }
237         
238         TaggableFactoryDecorator untag(Z tag) {
239             import std.algorithm : filter;
240             import std.array : array;
241             
242             this.tags_ = this.tags_.filter!(t => t != tag).array;
243             
244             return this;
245         }
246         
247         T factory() {
248             return this.decorated.factory;
249         }
250     }
251 }