1 /** 2 Contains primitives related to reference resolving during construction of data 3 (objects, structs, basic types, etc.). 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.reference; 34 35 import aermicioi.aedi.exception.invalid_cast_exception; 36 import aermicioi.aedi.factory.factory; 37 import aermicioi.aedi.storage.locator; 38 import aermicioi.aedi.storage.wrapper; 39 import std.traits; 40 41 /** 42 Represents a reference that some data is dependent on it. 43 44 Represents a reference that some data is dependent on it. 45 It will resolve itself to the referenced data, that is 46 subclass of Object, or data that is encapsulated in Wrapper object. 47 **/ 48 interface RuntimeReference { 49 50 /** 51 Resolve the reference, to referenced data. 52 53 Resolve the reference, to referenced data. 54 55 Params: 56 locator = an optional source of data used to resolve reference 57 58 Returns: 59 Object the actual object, or data that is wrapped in Wrapper object. 60 **/ 61 Object get(Locator!() locator); 62 } 63 64 /** 65 Represents a reference that is located in locator. 66 67 Represents a reference that is located in locator. 68 It uses referenced data's identity in locator to 69 find it and serve. 70 **/ 71 class LocatorReference : RuntimeReference { 72 private { 73 string identity_; 74 } 75 76 public { 77 /** 78 Constructor for LocatorReference 79 80 Params: 81 id = identity of component that is referenced 82 **/ 83 this(string id) { 84 this.identity = id; 85 } 86 87 @property { 88 89 /** 90 Set the identity of referenced data. 91 92 Set the identity of referenced data. 93 Description 94 95 Params: 96 identity = the identity of referenced data. 97 98 Returns: 99 this 100 **/ 101 LocatorReference identity(string identity) @safe nothrow { 102 this.identity_ = identity; 103 104 return this; 105 } 106 107 /** 108 Get the identity of referenced data. 109 110 Get the identity of referenced data. 111 112 Returns: 113 string the identity of referenced data 114 **/ 115 string identity() @safe nothrow { 116 return this.identity_; 117 } 118 } 119 120 /** 121 Resolve the reference, to referenced data. 122 123 Resolve the reference, to referenced data. 124 125 Params: 126 locator = an optional source of data used to resolve reference 127 128 Returns: 129 Object the actual object, or data that is wrapped in Wrapper object. 130 **/ 131 Object get(Locator!() locator) { 132 return locator.get(this.identity); 133 } 134 } 135 } 136 137 /** 138 ditto 139 **/ 140 auto lref(string id) { 141 return new LocatorReference(id); 142 } 143 144 /** 145 ditto 146 **/ 147 auto lref(string name)() { 148 return name.lref; 149 } 150 151 /** 152 Reference to a component stored in a locator by it's type. 153 **/ 154 class TypeLocatorReference(T) : RuntimeReference { 155 156 public { 157 /** 158 Resolve the reference, to referenced data. 159 160 Resolve the reference, to referenced data. 161 162 Params: 163 locator = an optional source of data used to resolve reference 164 165 Returns: 166 Object the actual object, or data that is wrapped in Wrapper object. 167 **/ 168 Object get(Locator!() locator) { 169 auto type = typeid(T); 170 171 if (locator.has(type.toString())) { 172 173 return locator.get(type.toString()); 174 } else { 175 176 return locator.get(fullyQualifiedName!T); 177 } 178 } 179 } 180 } 181 182 /** 183 ditto 184 **/ 185 auto lref(T)() { 186 return new TypeLocatorReference!T; 187 } 188 189 /** 190 Represents a reference to data yet to be constructed. 191 192 Represents a reference to data yet to be constructed. 193 It will instantiate the referenced data using an object 194 factory, and will serve it to requestor. 195 **/ 196 class AnonymousFactoryReference : RuntimeReference { 197 198 private { 199 ObjectFactory factory_; 200 } 201 202 public { 203 @property { 204 /** 205 Set factory 206 207 Params: 208 factory = factory used by anonymous reference to create component 209 Returns: 210 typeof(this) 211 **/ 212 AnonymousFactoryReference factory(ObjectFactory factory) @safe nothrow { 213 this.factory_ = factory; 214 215 return this; 216 } 217 218 /** 219 Get factory 220 221 Returns: 222 ObjectFactory 223 **/ 224 ObjectFactory factory() @safe nothrow { 225 return this.factory_; 226 } 227 } 228 229 /** 230 Resolve the reference, to referenced data. 231 232 Resolve the reference, to referenced data. 233 234 Params: 235 locator = an optional source of data used to resolve reference 236 237 Returns: 238 Object the actual object, or data that is wrapped in Wrapper object. 239 **/ 240 Object get(Locator!() locator) { 241 return this.factory.factory; 242 } 243 } 244 } 245 246 /** 247 ditto 248 **/ 249 auto anonymous(T : Factory!X, X)(T factory) { 250 import aermicioi.aedi.factory.wrapping_factory : WrappingFactory; 251 return anonymous(new WrappingFactory!T(factory)); 252 } 253 254 /** 255 ditto 256 **/ 257 auto anonymous(ObjectFactory factory) { 258 auto anonymous = new AnonymousFactoryReference(); 259 anonymous.factory = factory; 260 261 return anonymous; 262 } 263 264 /** 265 Resolve a reference, and attempt to convert to data of type T. 266 267 Resolve a reference, and attempt to convert to data of type T. 268 269 Params: 270 T = the expected type of resolved data. 271 locator = optional source of data for resolving reference 272 273 Throws: 274 InvalidCastException when resolved data is not of expected type. 275 276 Returns: 277 T referenced object 278 Wrapper!T referenced data that is not of Object subclass. 279 **/ 280 auto resolve(T : Object)(RuntimeReference reference, Locator!() locator) 281 body { 282 T result = cast(T) reference.get(locator); 283 284 if (result !is null) { 285 return result; 286 } 287 288 throw new InvalidCastException( 289 "Resolved runtime reference " ~ 290 typeid(reference.get(locator)).toString() ~ 291 " is not of expected type: " ~ 292 fullyQualifiedName!T 293 ); 294 } 295 296 /** 297 ditto 298 **/ 299 auto resolve(T)(RuntimeReference reference, Locator!() locator) 300 if (is(T == interface)) { 301 302 Object obj = reference.get(locator); 303 { 304 T result = cast(T) obj; 305 306 if (result !is null) { 307 return result; 308 } 309 } 310 311 { 312 Wrapper!T result = cast(Wrapper!T) obj; 313 314 if (result !is null) { 315 return result; 316 } 317 } 318 319 throw new InvalidCastException( 320 "Resolved runtime reference " ~ 321 typeid(reference.get(locator)).toString() ~ 322 " is not of expected type: " ~ 323 fullyQualifiedName!T 324 ); 325 } 326 327 /** 328 ditto 329 **/ 330 auto resolve(T)(RuntimeReference reference, Locator!() locator) 331 if (!is(T == interface)) { 332 333 Wrapper!T result = cast(Wrapper!T) reference.get(locator); 334 335 if (result !is null) { 336 return result; 337 } 338 339 throw new InvalidCastException( 340 "Resolved runtime reference " ~ 341 typeid(reference.get(locator)).toString() ~ 342 " is not of expected type: " ~ 343 fullyQualifiedName!T 344 ); 345 } 346 347 /** 348 ditto 349 **/ 350 auto ref Z resolve(T, Z)(auto ref Z reference, Locator!() locator) 351 if (!is(Z : RuntimeReference)) { 352 return reference; 353 } 354 355 /** 356 Alias to fullyQualifiedName from std.traits, for shorter notation. 357 **/ 358 template name(alias T) 359 if (is(typeof(T))) { 360 alias name = fullyQualifiedName!(typeof(T)); 361 } 362 363 /** 364 ditto 365 **/ 366 template name(T) { 367 alias name = fullyQualifiedName!T; 368 } 369 370 /** 371 Convert a type into a locator reference by type's name. 372 **/ 373 template toLref(Type) { 374 auto toLref() { 375 return name!Type.lref; 376 } 377 } 378 379 /** 380 ditto 381 **/ 382 template toLrefType(Type) { 383 alias toLrefType = LocatorReference; 384 }