1 /** 2 License: 3 Boost Software License - Version 1.0 - August 17th, 2003 4 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 27 Authors: 28 Alexandru Ermicioi 29 **/ 30 module aermicioi.aedi_property_reader.core.mapper; 31 32 import aermicioi.aedi_property_reader.core.exception; 33 import aermicioi.aedi_property_reader.core.convertor; 34 import aermicioi.aedi_property_reader.core.inspector; 35 import aermicioi.aedi_property_reader.core.setter; 36 import aermicioi.aedi_property_reader.core.accessor; 37 import aermicioi.aedi_property_reader.core.placeholder; 38 import std.experimental.allocator; 39 import std.experimental.logger; 40 import std.exception; 41 import std.algorithm; 42 import std.conv; 43 44 /** 45 Interface for components that are able to map from one type to another one. 46 **/ 47 interface Mapper(To, From = To) { 48 49 /** 50 Map from component to component. 51 52 Map from component to component, or transfer data from component to component 53 with optional conversion of data along the way. 54 55 Params: 56 from = original component that has it's data transferred 57 to = destination component that receives transferred data 58 allocator = optional allocator that could be used by convertors when doing field conversion 59 **/ 60 void map(From from, ref To to, RCIAllocator allocator = theAllocator); 61 62 @property { 63 /** 64 Set convertors 65 66 Params: 67 convertors = set a list of convertors to be used by mapper to automatically convert a mapped field to designated type 68 Returns: 69 typeof(this) 70 **/ 71 typeof(this) convertors(Convertor[] convertors) @safe nothrow pure; 72 73 /** 74 Get convertors 75 76 Returns: 77 Convertor[] 78 **/ 79 inout(Convertor[]) convertors() @safe nothrow pure inout; 80 81 /** 82 Set force 83 84 Params: 85 force = forces mapper to try and set a field even if it is not existent 86 87 Returns: 88 typeof(this) 89 **/ 90 typeof(this) force(bool force) @safe nothrow pure; 91 92 /** 93 Get force 94 95 Returns: 96 bool 97 **/ 98 inout(bool) force() @safe nothrow pure inout; 99 100 /** 101 Set conversion 102 103 Params: 104 conversion = whether to enable or not automatic conversion of fields using convertors. 105 106 Returns: 107 typeof(this) 108 **/ 109 typeof(this) conversion(bool conversion) @safe nothrow pure; 110 111 /** 112 Get conversion 113 114 Returns: 115 bool 116 **/ 117 inout(bool) conversion() @safe nothrow pure inout; 118 119 /** 120 Set skip 121 122 Params: 123 skip = whether to skip mapping of fields that have their type not identifiable in destination component 124 125 Returns: 126 typeof(this) 127 **/ 128 typeof(this) skip(bool skip) @safe nothrow pure; 129 130 /** 131 Get skip 132 133 Returns: 134 bool 135 **/ 136 inout(bool) skip() @safe nothrow pure inout; 137 } 138 } 139 140 /** 141 An implementation of a mapper that specifically converts From component To component. 142 143 An implementation of a mapper that specifically converts From component To component. 144 It will use inspectors for From and To component to get information about component fields 145 at runtime, and then use accessor and setter implementations to transfer data from one 146 component to another, with optional conversion of data using passed convertors. 147 **/ 148 class CompositeMapper(To, From) : Mapper!(To, From) { 149 150 private { 151 import std.typecons : Rebindable; 152 bool conversion_; 153 bool force_; 154 bool skip_; 155 156 Convertor[] convertors_; 157 158 Rebindable!(const PropertySetter!(To, Object)) setter_; 159 Rebindable!(const PropertyAccessor!(From, Object)) accessor_; 160 Rebindable!(const Inspector!From) fromInspector_; 161 Rebindable!(const Inspector!To) toInspector_; 162 } 163 164 public { 165 166 @property { 167 /** 168 Set convertors 169 170 Params: 171 convertors = a list of optional convertors used to convert from one format to another one 172 173 Returns: 174 typeof(this) 175 **/ 176 typeof(this) convertors(Convertor[] convertors) @safe nothrow pure { 177 this.convertors_ = convertors; 178 179 return this; 180 } 181 182 /** 183 Get convertors 184 185 Returns: 186 Convertor[] 187 **/ 188 inout(Convertor[]) convertors() @safe nothrow pure inout { 189 return this.convertors_; 190 } 191 192 /** 193 Set conversion 194 195 Params: 196 conversion = wether to convert or not values using convertors. 197 198 Returns: 199 typeof(this) 200 **/ 201 typeof(this) conversion(bool conversion) @safe nothrow pure { 202 this.conversion_ = conversion; 203 204 return this; 205 } 206 207 /** 208 Get conversion 209 210 Returns: 211 bool 212 **/ 213 inout(bool) conversion() @safe nothrow pure inout { 214 return this.conversion_; 215 } 216 217 /** 218 Set setter 219 220 Params: 221 setter = setter used to pass values to component. 222 223 Returns: 224 typeof(this) 225 **/ 226 typeof(this) setter(in PropertySetter!(To, Object) setter) @safe nothrow pure { 227 this.setter_ = setter; 228 229 return this; 230 } 231 232 /** 233 Get setter 234 235 Returns: 236 PropertySetter!(To, Object) 237 **/ 238 inout(const PropertySetter!(To, Object)) setter() @safe nothrow pure inout { 239 return this.setter_.get; 240 } 241 242 /** 243 Set accessor 244 245 Params: 246 accessor = property accessor used to extract values from mapped component 247 248 Returns: 249 typeof(this) 250 **/ 251 typeof(this) accessor(in PropertyAccessor!(From, Object) accessor) @safe nothrow pure { 252 this.accessor_ = accessor; 253 254 return this; 255 } 256 257 /** 258 Get accessor 259 260 Returns: 261 PropertyAccessor!(From, Object) 262 **/ 263 inout(const PropertyAccessor!(From, Object)) accessor() @safe nothrow pure inout { 264 return this.accessor_.get; 265 } 266 267 /** 268 Set fromInspector 269 270 Params: 271 fromInspector = inspector providing information about mapped component 272 273 Returns: 274 typeof(this) 275 **/ 276 typeof(this) fromInspector(in Inspector!From fromInspector) @safe nothrow pure { 277 this.fromInspector_ = fromInspector; 278 279 return this; 280 } 281 282 /** 283 Get fromInspector 284 285 Returns: 286 Inspector!From 287 **/ 288 inout(const Inspector!From) fromInspector() @safe nothrow pure inout { 289 return this.fromInspector_.get; 290 } 291 292 /** 293 Set toInspector 294 295 Params: 296 toInspector = inspector used to provide information about component that will store mapped data 297 298 Returns: 299 typeof(this) 300 **/ 301 typeof(this) toInspector(in Inspector!To toInspector) @safe nothrow pure { 302 this.toInspector_ = toInspector; 303 304 return this; 305 } 306 307 /** 308 Get toInspector 309 310 Returns: 311 Inspector!To 312 **/ 313 inout(const Inspector!To) toInspector() @safe nothrow pure inout { 314 return this.toInspector_.get; 315 } 316 317 /** 318 Set force 319 320 Params: 321 force = whether to force attempt in setting a property in a mapped component 322 323 Returns: 324 typeof(this) 325 **/ 326 typeof(this) force(bool force) @safe nothrow pure { 327 this.force_ = force; 328 329 return this; 330 } 331 332 /** 333 Get force 334 335 Returns: 336 bool 337 **/ 338 inout(bool) force() @safe nothrow pure inout { 339 return this.force_; 340 } 341 342 /** 343 Set skip 344 345 Params: 346 skip = whether to skip mapping of fields that have their type not identifiable in destination component 347 348 Returns: 349 typeof(this) 350 **/ 351 typeof(this) skip(bool skip) @safe nothrow pure { 352 this.skip_ = skip; 353 354 return this; 355 } 356 357 /** 358 Get skip 359 360 Returns: 361 bool 362 **/ 363 inout(bool) skip() @safe nothrow pure inout { 364 return this.skip_; 365 } 366 } 367 368 /** 369 Map from component to component. 370 371 Map from component to component, or transfer data from component to component 372 with optional conversion of data along the way. 373 374 Params: 375 from = original component that has it's data transferred 376 to = destination component that receives transferred data 377 allocator = optional allocator that could be used by convertors when doing field conversion 378 **/ 379 void map(From from, ref To to, RCIAllocator allocator = theAllocator) { 380 381 debug(trace) trace("Mapping ", this.fromInspector.properties(from), " of ", from.identify, " to ", to.identify); 382 foreach (property; this.fromInspector.properties(from)) { 383 384 debug(trace) trace("Migrating \"", property, "\" property "); 385 if (this.toInspector.has(to, property) || this.force) { 386 387 Object value = this.accessor.access(from, property); 388 import std.stdio; 389 390 if ( 391 (this.fromInspector.typeOf(from, property) != this.toInspector.typeOf(to, property)) 392 ) { 393 if (this.conversion) { 394 if (this.toInspector.typeOf(to, property) is typeid(void)) { 395 if (this.skip) { 396 debug(trace) trace("Skipping migration of \"", property, "\" due to missing type information in destination component"); 397 continue; 398 } 399 400 throw new ConvertorException(text( 401 "Cannot identify type of \"", property, "\" in destination component, probably missing" 402 )); 403 } 404 405 debug(trace) trace("\"", 406 property, 407 "\"'s type differs in original component and destination component, ", 408 this.fromInspector.typeOf(from, property), " and ", 409 this.toInspector.typeOf(to, property) 410 ); 411 412 auto compatible = convertors.filter!(c => 413 c.convertsFrom(this.fromInspector.typeOf(from, property)) && 414 c.convertsTo(this.toInspector.typeOf(to, property)) 415 ); 416 417 enforce!ConvertorException(!compatible.empty, text( 418 "Could not find convertor to convert \"", property, "\" from ", this.fromInspector.typeOf(from, property), 419 " to ", this.toInspector.typeOf(to, property) 420 )); 421 422 debug(trace) trace("Found convertor for \"", property, "\" from ", compatible.front.from, " to ", compatible.front.to); 423 424 value = compatible.front.convert(value, this.toInspector.typeOf(to, property), allocator); 425 } else { 426 427 throw new InvalidArgumentException(text( 428 "Invalid assignment \"", property, "\" has type of ", this.fromInspector.typeOf(from, property), 429 " in from component while in to component it is ", this.toInspector.typeOf(to, property) 430 )); 431 } 432 } 433 434 try { 435 436 this.setter.set( 437 to, 438 value, 439 property 440 ); 441 442 debug(trace) trace("Migrated \"", property, "\" from ", from.identify, " to ", to.identify); 443 } catch (Exception e) { 444 445 debug(trace) trace("Couldn't ", this.force ? "forcefully " : "", "set property \"", property, "\" to ", to.identify, " from ", from.identify, " due to ", e); 446 } 447 } else { 448 449 debug(trace) error(to.identify, " element does not have: ", property); 450 } 451 } 452 } 453 } 454 } 455 456 /** 457 An implementation of convertor that is using a mapper to map from component to component. 458 **/ 459 class CompositeConvertor(To, From) : CombinedConvertor { 460 import std.algorithm; 461 import std.array; 462 463 private { 464 Mapper!(To, From) mapper_; 465 } 466 467 public { 468 /** 469 Set used convertors 470 471 Params: 472 convertors = list of convertors to be used. 473 474 Returns: 475 typeof(this) 476 **/ 477 typeof(this) convertors(Convertor[] convertors) @safe nothrow { 478 this.mapper.convertors = convertors; 479 480 return this; 481 } 482 483 /** 484 Add a convertor to existing list 485 486 Params: 487 convertor = convertor to be added to 488 489 Returns: 490 typeof(this) 491 **/ 492 typeof(this) add(Convertor convertor) @safe nothrow { 493 this.mapper.convertors = this.mapper.convertors ~ convertor; 494 495 return this; 496 } 497 498 /** 499 Remove a convertor from existing list 500 501 Params: 502 convertor = convertor to be removed 503 504 Returns: 505 typeof(this) 506 **/ 507 typeof(this) remove(Convertor convertor) @trusted nothrow { 508 try { 509 this.mapper.convertors = this.mapper.convertors.filter!(c => c != convertor).array; 510 511 } catch (Exception e) { 512 assert(false, text("Failed to remove convertor due to ", e)); 513 } 514 515 return this; 516 } 517 518 @property { 519 /** 520 Set mapper 521 522 Params: 523 mapper = mapper used to map from component to component 524 525 Returns: 526 typeof(this) 527 **/ 528 typeof(this) mapper(Mapper!(To, From) mapper) @safe nothrow pure { 529 this.mapper_ = mapper; 530 531 return this; 532 } 533 534 /** 535 Get mapper 536 537 Returns: 538 Mapper!(To, From) 539 **/ 540 inout(Mapper!(To, From)) mapper() @safe nothrow pure inout { 541 return this.mapper_; 542 } 543 544 /** 545 Get the type info of component that convertor can convert from. 546 547 Get the type info of component that convertor can convert from. 548 The method is returning the default type that it is able to convert, 549 though it is not necessarily limited to this type only. More generalistic 550 checks should be done by convertsFrom method. 551 552 Returns: 553 type info of component that convertor is able to convert. 554 **/ 555 TypeInfo from() const { 556 return typeid(From); 557 } 558 559 /** 560 Get the type info of component that convertor is able to convert to. 561 562 Get the type info of component that convertor is able to convert to. 563 The method is returning the default type that is able to convert, 564 though it is not necessarily limited to this type only. More generalistic 565 checks should be done by convertsTo method. 566 567 Returns: 568 type info of component that can be converted to. 569 **/ 570 TypeInfo to() const { 571 return typeid(To); 572 } 573 } 574 575 /** 576 Check whether convertor is able to convert from. 577 578 Check whether convertor is able to convert from. 579 The intent of method is to implement customized type checking 580 is not limited immediatly to supported default from component. 581 582 Params: 583 from = the type info of component that could potentially be converted by convertor. 584 Returns: 585 true if it is able to convert from, or false otherwise. 586 **/ 587 bool convertsFrom(TypeInfo from) const { 588 return this.from is from; 589 } 590 591 /** 592 Check whether convertor is able to convert from. 593 594 Check whether convertor is able to convert from. 595 The method will try to extract type info out of from 596 object and use for subsequent type checking. 597 The intent of method is to implement customized type checking 598 is not limited immediatly to supported default from component. 599 600 Params: 601 from = the type info of component that could potentially be converted by convertor. 602 Returns: 603 true if it is able to convert from, or false otherwise. 604 **/ 605 bool convertsFrom(in Object from) const { 606 return this.convertsFrom(from.identify); 607 } 608 609 /** 610 Check whether convertor is able to convert to. 611 612 Check whether convertor is able to convert to. 613 The intent of the method is to implement customized type checking 614 that is not limited immediatly to supported default to component. 615 616 Params: 617 to = type info of component that convertor could potentially convert to. 618 619 Returns: 620 true if it is able to convert to, false otherwise. 621 **/ 622 bool convertsTo(TypeInfo to) const nothrow { 623 return this.to is to; 624 } 625 626 /** 627 Check whether convertor is able to convert to. 628 629 Check whether convertor is able to convert to. 630 The method will try to extract type info out of to object and use 631 for subsequent type checking. 632 The intent of the method is to implement customized type checking 633 that is not limited immediatly to supported default to component. 634 635 Params: 636 to = type info of component that convertor could potentially convert to. 637 638 Returns: 639 true if it is able to convert to, false otherwise. 640 **/ 641 bool convertsTo(in Object to) const nothrow { 642 return this.convertsTo(to.identify); 643 } 644 645 /** 646 Convert from component to component. 647 648 Params: 649 from = original component that is to be converted. 650 to = destination object that will be constructed out for original one. 651 allocator = optional allocator that could be used to construct to component. 652 Throws: 653 ConvertorException when there is a converting error 654 InvalidArgumentException when arguments passed are not of right type or state 655 Returns: 656 Resulting converted component. 657 **/ 658 Object convert(in Object from, TypeInfo to, RCIAllocator allocator = theAllocator) { 659 enforce!InvalidArgumentException(this.convertsFrom(from), text( 660 "Cannot convert ", from.identify, " to ", typeid(To), ", ", from.identify, " is not supported by ", typeid(this) 661 )); 662 663 enforce!InvalidArgumentException(this.convertsTo(to), text( 664 "Cannot convert ", from.identify, " to ", typeid(To), ", ", to, " is not supported by ", typeid(this) 665 )); 666 667 static if (is(To : Object)) { 668 To placeholder = allocator.make!To; 669 this.mapper.map(from.unwrap!From, placeholder, allocator); 670 } else { 671 auto placeholder = allocator.make!(PlaceholderImpl!To)(To.init); 672 this.mapper.map(from.unwrap!From, placeholder.value, allocator); 673 } 674 675 return placeholder; 676 } 677 678 /** 679 Destroy component created using this convertor. 680 681 Destroy component created using this convertor. 682 Since convertor could potentially allocate memory for 683 converted component, only itself is containing history of allocation, 684 and therefore it is responsible as well to destroy and free allocated 685 memory with allocator. 686 687 Params: 688 converted = component that should be destroyed. 689 allocator = allocator used to allocate converted component. 690 **/ 691 void destruct(ref Object converted, RCIAllocator allocator = theAllocator) { 692 enforce!InvalidArgumentException(this.convertsFrom(from), text( 693 "Cannot destruct ", from.identify, " to ", typeid(To), " not supported by ", typeid(this) 694 )); 695 696 allocator.dispose(converted); 697 converted = Object.init; 698 } 699 } 700 } 701 702 /** 703 An implementation of mapper, that works solely with components that have their type erased. 704 705 An implementation of mapper, that works solely with components that have their type erased. 706 At runtime it will attempt to match inspectors, accessor and setter for original component and 707 destination, then use them to create a specific mapper for that configuration and use it to 708 transfer data from origin component to destination one. If no matches are found, no transfer is performed 709 and an exception should be thrown. 710 **/ 711 class RuntimeMapper : Mapper!(Object, Object) { 712 713 private { 714 bool conversion_; 715 bool force_; 716 bool skip_; 717 718 Convertor[] convertors_; 719 720 PropertyAccessor!Object[] accessors_; 721 PropertySetter!Object[] setters_; 722 Inspector!Object[] inspectors_; 723 Mapper!Object delegate ( 724 in PropertyAccessor!Object, 725 in PropertySetter!Object, 726 in Inspector!Object, 727 in Inspector!Object 728 ) factory_; 729 730 void delegate(Mapper!Object) destructor_; 731 } 732 733 public { 734 @property { 735 /** 736 Set convertors 737 738 Params: 739 convertors = a list of convertors that could optionally be used to convert mapped fields 740 741 Returns: 742 typeof(this) 743 **/ 744 typeof(this) convertors(Convertor[] convertors) @safe nothrow pure { 745 this.convertors_ = convertors; 746 747 return this; 748 } 749 750 /** 751 Get convertors 752 753 Returns: 754 Convertor[] 755 **/ 756 inout(Convertor[]) convertors() @safe nothrow pure inout { 757 return this.convertors_; 758 } 759 760 /** 761 Set conversion 762 763 Params: 764 conversion = whether to automatically convert or not mapped fields to desired type 765 766 Returns: 767 typeof(this) 768 **/ 769 typeof(this) conversion(bool conversion) @safe nothrow pure { 770 this.conversion_ = conversion; 771 772 return this; 773 } 774 775 /** 776 Get conversion 777 778 Returns: 779 bool 780 **/ 781 inout(bool) conversion() @safe nothrow pure inout { 782 return this.conversion_; 783 } 784 785 /** 786 Set force 787 788 Params: 789 force = whether force or not an attempt to set an inexistent field. 790 791 Returns: 792 typeof(this) 793 **/ 794 typeof(this) force(bool force) @safe nothrow pure { 795 this.force_ = force; 796 797 return this; 798 } 799 800 /** 801 Get force 802 803 Returns: 804 bool 805 **/ 806 inout(bool) force() @safe nothrow pure inout { 807 return this.force_; 808 } 809 810 /** 811 Set skip 812 813 Params: 814 skip = whether to skip mapping of fields that have their type not identifiable in destination component 815 816 Returns: 817 typeof(this) 818 **/ 819 typeof(this) skip(bool skip) @safe nothrow pure { 820 this.skip_ = skip; 821 822 return this; 823 } 824 825 /** 826 Get skip 827 828 Returns: 829 bool 830 **/ 831 inout(bool) skip() @safe nothrow pure inout { 832 return this.skip_; 833 } 834 835 /** 836 Set factory 837 838 Params: 839 factory = factory used to create a mapper 840 841 Returns: 842 typeof(this) 843 **/ 844 typeof(this) factory(Mapper!Object delegate ( 845 in PropertyAccessor!Object, 846 in PropertySetter!Object, 847 in Inspector!Object, 848 in Inspector!Object 849 ) factory) @safe nothrow pure { 850 this.factory_ = factory; 851 852 return this; 853 } 854 855 /** 856 Get factory 857 858 Returns: 859 Mapper!Object delegate () 860 **/ 861 inout(Mapper!Object delegate ( 862 in PropertyAccessor!Object, 863 in PropertySetter!Object, 864 in Inspector!Object, 865 in Inspector!Object 866 )) factory() @safe nothrow pure inout { 867 return this.factory_; 868 } 869 870 /** 871 Set destructor 872 873 Params: 874 destructor = destructor used to destroy created mapper 875 876 Returns: 877 typeof(this) 878 **/ 879 typeof(this) destructor(void delegate(Mapper!Object) destructor) @safe nothrow pure { 880 this.destructor_ = destructor; 881 882 return this; 883 } 884 885 /** 886 Get destructor 887 888 Returns: 889 void delegate(Mapper!Object) 890 **/ 891 inout(void delegate(Mapper!Object)) destructor() @safe nothrow pure inout { 892 return this.destructor_; 893 } 894 895 /** 896 Set accessors 897 898 Params: 899 accessors = list of runtime accessors used to access data 900 901 Returns: 902 typeof(this) 903 **/ 904 typeof(this) accessors(PropertyAccessor!Object[] accessors) @safe nothrow pure { 905 this.accessors_ = accessors; 906 907 return this; 908 } 909 910 /** 911 Get accessors 912 913 Returns: 914 PropertyAccessor!Object[] 915 **/ 916 inout(PropertyAccessor!Object[]) accessors() @safe nothrow pure inout { 917 return this.accessors_; 918 } 919 920 /** 921 Set setters 922 923 Params: 924 setters = list of runtime setters used to map from one to another 925 926 Returns: 927 typeof(this) 928 **/ 929 typeof(this) setters(PropertySetter!Object[] setters) @safe nothrow pure { 930 this.setters_ = setters; 931 932 return this; 933 } 934 935 /** 936 Get setters 937 938 Returns: 939 PropertySetter!Object[] 940 **/ 941 inout(PropertySetter!Object[]) setters() @safe nothrow pure inout { 942 return this.setters_; 943 } 944 945 /** 946 Set inspectors 947 948 Params: 949 inspectors = list of runtime inspectors used to inspect various components 950 951 Returns: 952 typeof(this) 953 **/ 954 typeof(this) inspectors(Inspector!Object[] inspectors) @safe nothrow pure { 955 this.inspectors_ = inspectors; 956 957 return this; 958 } 959 960 /** 961 Get inspectors 962 963 Returns: 964 Inspector!Object[] 965 **/ 966 inout(Inspector!Object[]) inspectors() @safe nothrow pure inout { 967 return this.inspectors_; 968 } 969 970 } 971 972 /** 973 Map from component to component. 974 975 Map from component to component, or transfer data from component to component 976 with optional conversion of data along the way. 977 978 Params: 979 from = original component that has it's data transferred 980 to = destination component that receives transferred data 981 allocator = optional allocator that could be used by convertors when doing field conversion 982 Throws: 983 InvalidArgumentException when no either accessor, setter, or inspector is found. 984 **/ 985 void map(Object from, ref Object to, RCIAllocator allocator = theAllocator) { 986 auto accessors = this.accessors.filter!(accessor => accessor.componentType(from) is from.identify); 987 auto setters = this.setters.filter!(setter => setter.componentType(to) is to.identify); 988 auto fromInspectors = this.inspectors.filter!(inspector => inspector.typeOf(from) is from.identify); 989 auto toInspectors = this.inspectors.filter!(inspector => inspector.typeOf(to) is to.identify); 990 991 enforce!InvalidArgumentException(!accessors.empty, text("No field accessor for ", from.identify, " has been provided, cannot map to ", to.identify)); 992 enforce!InvalidArgumentException(!setters.empty, text("No field setter for ", to.identify, " has been provided, cannot map from ", from.identify)); 993 enforce!InvalidArgumentException(!fromInspectors.empty, text("No inspector for ", from.identify, " has been provided, cannot map to ", to.identify)); 994 enforce!InvalidArgumentException(!toInspectors.empty, text("No inspector for ", to.identify, " has been provided, cannot map from ", to.identify)); 995 996 import std.stdio; 997 writeln(to.identify); 998 auto mapper = this.factory()( 999 accessors.front, 1000 setters.front, 1001 fromInspectors.front, 1002 toInspectors.front 1003 ); 1004 mapper.force = this.force; 1005 mapper.conversion = this.conversion; 1006 mapper.skip = this.skip; 1007 mapper.convertors = this.convertors; 1008 1009 mapper.map(from, to, allocator); 1010 1011 this.destructor()(mapper); 1012 } 1013 1014 } 1015 }