1 /** 2 This module implements annotation based configuration of containers. 3 4 License: 5 Boost Software License - Version 1.0 - August 17th, 2003 6 7 Permission is hereby granted, free of charge, to any person or organization 8 obtaining a copy of the software and accompanying documentation covered by 9 this license (the "Software") to use, reproduce, display, distribute, 10 execute, and transmit the Software, and to prepare derivative works of the 11 Software, and to permit third-parties to whom the Software is furnished to 12 do so, all subject to the following: 13 14 The copyright notices in the Software and this entire statement, including 15 the above license grant, this restriction and the following disclaimer, 16 must be included in all copies of the Software, in whole or in part, and 17 all derivative works of the Software, unless such copies or derivative 18 works are solely in the form of machine-executable object code generated by 19 a source language processor. 20 21 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 22 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 23 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 24 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 25 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 26 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 27 DEALINGS IN THE SOFTWARE. 28 29 Authors: 30 Alexandru Ermicioi 31 **/ 32 module aermicioi.aedi.configurer.annotation.annotation; 33 34 public import aermicioi.aedi.factory.reference : lref, anonymous; 35 36 import aermicioi.aedi.storage.locator; 37 import aermicioi.aedi.storage.allocator_aware; 38 import aermicioi.aedi.storage.storage; 39 import aermicioi.aedi.storage.wrapper; 40 import aermicioi.aedi.container.container; 41 import aermicioi.aedi.factory.factory; 42 import aermicioi.aedi.factory.reference; 43 import aermicioi.aedi.factory.generic_factory; 44 import aermicioi.aedi.factory.proxy_factory; 45 import aermicioi.aedi.exception; 46 import aermicioi.aedi.util.traits; 47 48 import std.traits; 49 import std.meta; 50 import std.conv : to; 51 import std.algorithm; 52 import std.experimental.allocator; 53 import std.experimental.allocator.gc_allocator; 54 import std.experimental.allocator.mmap_allocator; 55 import std.experimental.allocator.mallocator; 56 57 @safe: 58 59 /** 60 Check if T is instance of ComponentAnnotation 61 **/ 62 enum bool isComponentAnnotation(T) = is(T : ComponentAnnotation); 63 64 /** 65 ditto 66 **/ 67 enum bool isComponentAnnotation(alias T) = isComponentAnnotation!(toType!T); 68 69 /** 70 Annotation used to denote a component that should be stored into an container. 71 **/ 72 struct ComponentAnnotation { 73 74 } 75 76 /** 77 ditto 78 **/ 79 alias component = ComponentAnnotation; 80 81 /** 82 Check if T is instance of ValueAnnotation 83 **/ 84 enum bool isValueAnnotation(T) = is(T : ValueAnnotation!Value, Value); 85 86 /** 87 ditto 88 **/ 89 enum bool isValueAnnotation(alias T) = isValueAnnotation!(toType!T); 90 91 /** 92 Construct the instance using value provided in annotation 93 94 Params: 95 value = value that should be component created with 96 97 **/ 98 struct ValueAnnotation(Value) { 99 100 /** 101 value = value that should be component created with 102 **/ 103 Value value; 104 } 105 106 /** 107 ditto 108 **/ 109 ValueAnnotation!T value(T)(T value) { 110 return ValueAnnotation!T(value); 111 } 112 113 /** 114 Check if T is instance of AllocatorAnnotation 115 **/ 116 enum bool isAllocatorAnnotation(T) = is(T : AllocatorAnnotation!X, X); 117 118 /** 119 ditto 120 **/ 121 enum bool isAllocatorAnnotation(alias T) = isAllocatorAnnotation!(toType!T); 122 123 /** 124 Use allocator to allocate component. 125 126 Params: 127 allocator = allocator used to allocate the component 128 **/ 129 struct AllocatorAnnotation(T = RCIAllocator) 130 if (!hasStaticMember!(T, "instance")) { 131 132 /** 133 Allocator to use for component allocation. 134 **/ 135 T allocator; 136 137 /** 138 Get iallocator 139 140 Returns: 141 RCIAllocator 142 **/ 143 RCIAllocator iallocator() { 144 return this.allocator.allocatorObject; 145 } 146 } 147 148 /** 149 ditto 150 **/ 151 struct AllocatorAnnotation(T) 152 if (hasStaticMember!(T, "instance")) { 153 154 /** 155 Allocator to use for component allocation. 156 **/ 157 T allocator; 158 159 /** 160 Get iallocator 161 162 Returns: 163 RCIAllocator 164 **/ 165 RCIAllocator iallocator() @trusted { 166 return T.instance.allocatorObject; 167 } 168 } 169 170 /** 171 ditto 172 **/ 173 AllocatorAnnotation!T allocator(T)(T allocator) { 174 return AllocatorAnnotation!T(allocator); 175 } 176 177 /** 178 ditto 179 **/ 180 AllocatorAnnotation!T allocator(T : GCAllocator)() { 181 return AllocatorAnnotation!T(); 182 } 183 184 /** 185 ditto 186 **/ 187 AllocatorAnnotation!T allocator(T : MmapAllocator)() { 188 return AllocatorAnnotation!T(); 189 } 190 191 /** 192 ditto 193 **/ 194 AllocatorAnnotation!T allocator(T : Mallocator)() { 195 return AllocatorAnnotation!T(); 196 } 197 198 /** 199 Check if T is instance of ConstructorAnnotation 200 **/ 201 enum bool isConstructorAnnotation(T) = is(T : ConstructorAnnotation!Z, Z...); 202 203 /** 204 ditto 205 **/ 206 enum bool isConstructorAnnotation(alias T) = isConstructorAnnotation!(toType!T); 207 /** 208 Annotation used to mark a constructor to be used for component instantiation. 209 210 Params: 211 Args = tuple of argument types for arguments to be passed into a constructor. 212 **/ 213 struct ConstructorAnnotation(Args...) { 214 215 /** 216 List of arguments for constructor 217 **/ 218 Args args; 219 220 /** 221 Constructor accepting a list of arguments, that will be passed to constructor. 222 223 Params: 224 args = arguments passed to component's constructor 225 **/ 226 this(Args args) { 227 this.args = args; 228 } 229 } 230 231 /** 232 ditto 233 **/ 234 auto constructor(Args...)(Args args) { 235 return ConstructorAnnotation!Args(args); 236 } 237 238 /** 239 Check if T is instance of SetterAnnotation 240 **/ 241 enum bool isSetterAnnotation(T) = is(T : SetterAnnotation!Z, Z...); 242 243 /** 244 ditto 245 **/ 246 enum bool isSetterAnnotation(alias T) = isSetterAnnotation!(toType!T); 247 /** 248 Annotation used to mark a member to be called or set (in case of fields), with args passed to setter. 249 250 Note: if an overloaded method is annotated with Setter, the method from overload set that matches argument list in Setter annotation 251 will be called. 252 253 Params: 254 Args = the argument types of arguments passed to method 255 **/ 256 struct SetterAnnotation(Args...) { 257 258 /** 259 Arguments passed to method 260 **/ 261 Args args; 262 263 /** 264 Constructor accepting a list of arguments, that will be passed to method, or set to a field. 265 266 Params: 267 args = arguments passed to component's constructor 268 **/ 269 this(Args args) { 270 this.args = args; 271 } 272 } 273 274 /** 275 ditto 276 **/ 277 auto setter(Args...)(Args args) { 278 return SetterAnnotation!Args(args); 279 } 280 281 /** 282 Check if T is instance of CallbackFactoryAnnotation 283 **/ 284 enum bool isCallbackFactoryAnnotation(T) = is(T : CallbackFactoryAnnotation!Z, Z...); 285 286 /** 287 ditto 288 **/ 289 enum bool isCallbackFactoryAnnotation(alias T) = isCallbackFactoryAnnotation!(toType!T); 290 /** 291 Annotation that specifies a delegate to be used to instantiate component. 292 293 Params: 294 Z = the type of component that will be returned by the delegate 295 Args = type tuple of args that can be passed to delegate. 296 **/ 297 struct CallbackFactoryAnnotation(Z, Dg, Args...) 298 if ((is(Dg == Z delegate (RCIAllocator, Locator!(), Args)) || is(Dg == Z function (RCIAllocator, Locator!(), Args)))) { 299 300 /** 301 Arguments that can be passed to delegate. 302 **/ 303 Args args; 304 305 /** 306 Delegate that is used to create component 307 **/ 308 Dg dg; 309 310 /** 311 Constructor accepting a factory delegate, and it's arguments. 312 313 Params: 314 dg = delegate that will factory a component 315 args = list of arguments passed to delegate. 316 **/ 317 this(Dg dg, ref Args args) { 318 this.dg = dg; 319 this.args = args; 320 } 321 } 322 323 /** 324 ditto 325 **/ 326 auto fact(T, Args...)(T delegate(RCIAllocator, Locator!(), Args) dg, Args args) { 327 return CallbackFactoryAnnotation!(T, T delegate(RCIAllocator, Locator!(), Args), Args)(dg, args); 328 } 329 330 /** 331 ditto 332 **/ 333 auto fact(T, Args...)(T function(RCIAllocator, Locator!(), Args) dg, Args args) { 334 return CallbackFactoryAnnotation!(T, T function(RCIAllocator, Locator!(), Args), Args)(dg, args); 335 } 336 337 /** 338 Check if T is instance of CallbackConfigurerAnnotation 339 **/ 340 enum bool isCallbackConfigurerAnnotation(T) = is(T : CallbackConfigurerAnnotation!Z, Z...); 341 342 /** 343 ditto 344 **/ 345 enum bool isCallbackConfigurerAnnotation(alias T) = isCallbackConfigurerAnnotation!(toType!T); 346 /** 347 Annotation that specifies a delegate to be used to configure component somehow. 348 349 Params: 350 Z = the type of component that will be returned by the delegate 351 Args = type tuple of args that can be passed to delegate. 352 **/ 353 struct CallbackConfigurerAnnotation(Z, Dg, Args...) 354 if ( 355 is(Dg == void delegate (Locator!(), Z, Args)) || 356 is(Dg == void function (Locator!(), Z, Args)) || 357 is(Dg == void delegate (Locator!(), ref Z, Args)) || 358 is(Dg == void function (Locator!(), ref Z, Args)) 359 ){ 360 361 /** 362 Args that can be passed to delegate 363 **/ 364 Args args; 365 366 /** 367 Delegate that is used to configure component 368 **/ 369 Dg dg; 370 371 /** 372 Constructor accepting a configurer delegate, and it's arguments. 373 374 Params: 375 dg = delegate that will be used to configure a component 376 args = list of arguments passed to delegate. 377 **/ 378 this(Dg dg, ref Args args) { 379 this.dg = dg; 380 this.args = args; 381 } 382 } 383 384 /** 385 ditto 386 **/ 387 auto callback(T, Args...)(void delegate (Locator!(), ref T, Args) dg, Args args) { 388 return CallbackConfigurerAnnotation!(T, void delegate (Locator!(), ref T, Args), Args)(dg, args); 389 } 390 391 /** 392 ditto 393 **/ 394 auto callback(T, Args...)(void function (Locator!(), ref T, Args) dg, Args args) { 395 return CallbackConfigurerAnnotation!(T, void function (Locator!(), ref T, Args), Args)(dg, args); 396 } 397 398 /** 399 ditto 400 **/ 401 auto callback(T, Args...)(void delegate (Locator!(), T, Args) dg, Args args) { 402 return CallbackConfigurerAnnotation!(T, void delegate (Locator!(), T, Args), Args)(dg, args); 403 } 404 405 /** 406 ditto 407 **/ 408 auto callback(T, Args...)(void function (Locator!(), T, Args) dg, Args args) { 409 return CallbackConfigurerAnnotation!(T, void function (Locator!(), T, Args), Args)(dg, args); 410 } 411 412 /** 413 Check if T is instance of AutowiredAnnotation 414 **/ 415 enum bool isAutowiredAnnotation(T) = is(T : AutowiredAnnotation); 416 417 /** 418 ditto 419 **/ 420 enum bool isAutowiredAnnotation(alias T) = isAutowiredAnnotation!(toType!T); 421 422 /** 423 Annotation used to mark constructor or method for auto wiring. 424 425 Marking a method/constructor with autowired annotation will make container to call it with arguments fetched from 426 locator by types of them. 427 428 Note: even if a method/constructor from an overloaded set is marked with autowired annotation, the first method from overload set 429 will be used. Due to that autowired annotation is recommended to use on methods/constrcutors that are not overloaded. 430 431 **/ 432 struct AutowiredAnnotation { 433 434 } 435 436 /** 437 ditto 438 **/ 439 alias autowired = AutowiredAnnotation; 440 441 /** 442 Check if T is instance of QualifierAnnotation 443 **/ 444 enum bool isQualifierAnnotation(T) = is(T : QualifierAnnotation); 445 446 /** 447 ditto 448 **/ 449 enum bool isQualifierAnnotation(alias T) = isQualifierAnnotation!(toType!T); 450 451 /** 452 An annotation used to provide custom identity for an object in container. 453 **/ 454 struct QualifierAnnotation { 455 /** 456 Identity of component 457 **/ 458 string id; 459 } 460 461 /** 462 An annotation used to provide custom identity for an object in container. 463 464 This function is a convenince function to automatically infer required types for underlying annotation. 465 466 Params: 467 id = identity of object in container 468 **/ 469 QualifierAnnotation qualifier(string id) { 470 return QualifierAnnotation(id); 471 } 472 473 /** 474 ditto 475 **/ 476 QualifierAnnotation qualifier(string id)() { 477 return QualifierAnnotation(id); 478 } 479 480 /** 481 An annotation used to provide custom identity for an object in container by some interface. 482 483 This function is a convenince function to automatically infer required types for underlying annotation. 484 485 Params: 486 I = identity of object in container 487 **/ 488 QualifierAnnotation qualifier(I)() { 489 return QualifierAnnotation(name!I); 490 } 491 492 /** 493 Check if T is instance of ContainedAnnotation 494 **/ 495 enum bool isContainedAnnotation(T) = is(T : ContainedAnnotation); 496 497 /** 498 ditto 499 **/ 500 enum bool isContainedAnnotation(alias T) = isContainedAnnotation!(toType!T); 501 /** 502 When objects are registered into a component container, this annotation marks in which sub-container it is required to store. 503 **/ 504 struct ContainedAnnotation { 505 /** 506 The id of container which will manage component. 507 **/ 508 string id; 509 } 510 511 /** 512 When objects are registered into a component container, this annotation marks in which sub-container it is required to store. 513 514 This function is a convenince function to automatically infer required types for underlying annotation. 515 516 Params: 517 id = identity of container where to store the object. 518 **/ 519 ContainedAnnotation contained(string id) { 520 return ContainedAnnotation(id); 521 } 522 523 /** 524 Check if T is instance of CallbackDestructor 525 **/ 526 enum bool isCallbackDestructor(T) = is(T) && is(T == DefaultDestructor); 527 528 /** 529 ditto 530 **/ 531 enum bool isCallbackDestructor(alias T) = is(typeof(T)); 532 533 /** 534 Use callback stored in annotation to destroy a component of type T 535 536 Params: 537 dg = callback used to destroy the component 538 args = arguments passed to callback to destroy the component 539 **/ 540 struct CallbackDestructor(T, Dg : void delegate(RCIAllocator, ref T destructable, Args), Args...) { 541 /** 542 Callback used to destroy the component 543 **/ 544 Dg dg; 545 546 /** 547 Arguments passed to callback to destroy the component 548 **/ 549 Args args; 550 } 551 552 /** 553 ditto 554 **/ 555 CallbackDestructor callbackDestructor(T, Dg : void delegate(RCIAllocator, ref T destructable, Args), Args...)(Dg dg, Args args) { 556 return CallbackDestructor(dg, args); 557 } 558 559 /** 560 Check if T is instance of DestructorMethod 561 **/ 562 enum bool isDestructorMethod(T) = is(T) && is(T == DefaultDestructor); 563 564 /** 565 ditto 566 **/ 567 enum bool isDestructorMethod(alias T) = is(typeof(T)); 568 569 /** 570 Use method from instance of type T to destroy a component of type Z 571 572 Params: 573 method = method used to destroy component of type Z 574 args = list of arguments to pass to destructor method 575 **/ 576 struct DestructorMethod(string method, T, Z, Args...) { 577 578 /** 579 List of arguments to pass to destructor method 580 **/ 581 Args args; 582 } 583 584 /** 585 ditto 586 **/ 587 CallbackDestructor destructorMethod(string method, T, Z, Args...)() { 588 return DestructorMethod(dg, args); 589 }