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.factory.factory; 36 import aermicioi.aedi.exception.invalid_cast_exception; 37 import aermicioi.aedi.storage.wrapper; 38 import aermicioi.aedi.storage.locator; 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 this(string id) { 78 this.identity = id; 79 } 80 81 @property { 82 83 /** 84 Set the identity of referenced data. 85 86 Set the identity of referenced data. 87 Description 88 89 Params: 90 identity = the identity of referenced data. 91 92 Returns: 93 this 94 **/ 95 LocatorReference identity(string identity) @safe nothrow { 96 this.identity_ = identity; 97 98 return this; 99 } 100 101 /** 102 Get the identity of referenced data. 103 104 Get the identity of referenced data. 105 106 Returns: 107 string the identity of referenced data 108 **/ 109 string identity() @safe nothrow { 110 return this.identity_; 111 } 112 } 113 114 Object get(Locator!() locator) { 115 return locator.get(this.identity); 116 } 117 } 118 } 119 120 /** 121 ditto 122 **/ 123 auto lref(string id) { 124 return new LocatorReference(id); 125 } 126 127 /** 128 ditto 129 **/ 130 auto lref(T)() { 131 import std.traits; 132 133 return (name!T).lref; 134 } 135 136 /** 137 ditto 138 **/ 139 auto lref(string name)() { 140 return name.lref; 141 } 142 143 /** 144 Represents a reference to data yet to be constructed. 145 146 Represents a reference to data yet to be constructed. 147 It will instantiate the referenced data using an object 148 factory, and will serve it to requestor. 149 **/ 150 class AnonymousFactoryReference : RuntimeReference { 151 152 private { 153 ObjectFactory factory_; 154 } 155 156 public { 157 @property { 158 AnonymousFactoryReference factory(ObjectFactory factory) @safe nothrow { 159 this.factory_ = factory; 160 161 return this; 162 } 163 164 ObjectFactory factory() @safe nothrow { 165 return this.factory_; 166 } 167 } 168 169 Object get(Locator!() locator) { 170 return this.factory.factory; 171 } 172 } 173 } 174 175 /** 176 ditto 177 **/ 178 auto anonymous(T : Factory!X, X)(T factory) { 179 import aermicioi.aedi.factory.decorating_factory; 180 return anonymous(new WrappingFactory!T(factory)); 181 } 182 183 /** 184 ditto 185 **/ 186 auto anonymous(ObjectFactory factory) { 187 import aermicioi.aedi.factory.decorating_factory; 188 189 auto anonymous = new AnonymousFactoryReference(); 190 anonymous.factory = factory; 191 192 return anonymous; 193 } 194 195 /** 196 Resolve a reference, and attempt to convert to data of type T. 197 198 Resolve a reference, and attempt to convert to data of type T. 199 200 Params: 201 T = the expected type of resolved data. 202 locator = optional source of data for resolving reference 203 204 Throws: 205 InvalidCastException when resolved data is not of expected type. 206 207 Returns: 208 T referenced object 209 Wrapper!T referenced data that is not of Object subclass. 210 **/ 211 auto resolve(T : Object)(RuntimeReference reference, Locator!() locator) 212 body { 213 T result = cast(T) reference.get(locator); 214 215 if (result !is null) { 216 return result; 217 } 218 219 throw new InvalidCastException("Resolved runtime reference " ~ typeid(reference.get(locator)).toString() ~ " is not of expected type: " ~ fullyQualifiedName!T); 220 } 221 222 /** 223 ditto 224 **/ 225 auto resolve(T)(RuntimeReference reference, Locator!() locator) 226 if (is(T == interface)) { 227 228 Object obj = reference.get(locator); 229 { 230 T result = cast(T) obj; 231 232 if (result !is null) { 233 return result; 234 } 235 } 236 237 { 238 Wrapper!T result = cast(Wrapper!T) obj; 239 240 if (result !is null) { 241 return result; 242 } 243 } 244 245 throw new InvalidCastException("Resolved runtime reference " ~ typeid(reference.get(locator)).toString() ~ " is not of expected type: " ~ fullyQualifiedName!T); 246 } 247 248 /** 249 ditto 250 **/ 251 auto resolve(T)(RuntimeReference reference, Locator!() locator) 252 if (!is(T == interface)) { 253 254 Wrapper!T result = cast(Wrapper!T) reference.get(locator); 255 256 if (result !is null) { 257 return result; 258 } 259 260 throw new InvalidCastException("Resolved runtime reference " ~ typeid(reference.get(locator)).toString() ~ " is not of expected type: " ~ fullyQualifiedName!T); 261 } 262 263 /** 264 ditto 265 **/ 266 auto ref Z resolve(T, Z)(auto ref Z reference, Locator!() locator) 267 if (!is(Z : RuntimeReference)) { 268 return reference; 269 } 270 271 /** 272 Alias to fullyQualifiedName from std.traits, for shorter notation. 273 **/ 274 template name(alias T) 275 if (is(typeof(T))) { 276 alias name = fullyQualifiedName!(typeof(T)); 277 } 278 279 /** 280 ditto 281 **/ 282 template name(T) { 283 alias name = fullyQualifiedName!T; 284 } 285 286 /** 287 Convert a type into a locator reference by type's name. 288 **/ 289 template toLref(Type) { 290 auto toLref() { 291 return name!Type.lref; 292 } 293 } 294 295 /** 296 ditto 297 **/ 298 template toLrefType(Type) { 299 alias toLrefType = LocatorReference; 300 }