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 }