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 moduleaermicioi.aedi_property_reader.core.accessor;
31 32 importaermicioi.aedi.storage.allocator_aware;
33 importaermicioi.aedi.exception.not_found_exception;
34 importaermicioi.aedi.exception.invalid_cast_exception;
35 importaermicioi.aedi_property_reader.core.exception;
36 importaermicioi.util.traits;
37 importaermicioi.aedi_property_reader.core.traits : isD, n;
38 importaermicioi.aedi_property_reader.core.placeholder;
39 importtaggedalgebraic;
40 importstd.array;
41 importstd.conv;
42 importstd.algorithm;
43 importstd.range;
44 importstd.exception : enforce;
45 importstd.variant;
46 importstd.traits;
47 importstd.meta;
48 importstd.experimental.logger;
49 50 /**
51 Interface for objects that are able to get child component out of parent one.
52 53 The intent of property accessor is to provide runtime means of accessing various properties
54 out of a component which could be a D object, or struct. The implementation is free in allocation
55 policies in order to satisfy the property access, though the burden of freeing allocated memory
56 is left on code using the accessor.
57 **/58 interfacePropertyAccessor(ComponentType, FieldType = ComponentType, KeyType = string) {
59 60 61 /**
62 Get a property out of component
63 64 Params:
65 component = a component which has some properties identified by property.
66 Throws:
67 NotFoundException in case when no requested property is available.
68 InvalidArgumentException in case when passed arguments are somehow invalid for use.
69 Returns:
70 FieldType accessed property.
71 **/72 FieldTypeaccess(ComponentTypecomponent, inKeyTypeproperty) const;
73 74 /**
75 Check if requested property is present in component.
76 77 Check if requested property is present in component.
78 The method could have allocation side effects due to the fact that
79 it is not restricted in calling access method of the accessor.
80 81 Params:
82 component = component which is supposed to have property
83 property = speculated property that is to be tested if it is present in component
84 Returns:
85 true if property is in component
86 **/87 boolhas(inComponentTypecomponent, inKeyTypeproperty) constnothrow;
88 89 /**
90 Identify the type of supported component.
91 92 Identify the type of supported component. It returns type info of component
93 if it is supported by accessor, otherwise it will return typeid(void) denoting that
94 the type isn't supported by accessor. The accessor is not limited to returning the type
95 info of passed component, it can actually return type info of super type or any type
96 given the returned type is implicitly convertible or castable to ComponentType.
97 98 Params:
99 component = the component for which accessor should identify the underlying type
100 101 Returns:
102 TypeInfo type information about passed component, or typeid(void) if component is not supported.
103 **/104 TypeInfocomponentType(ComponentTypecomponent) constnothrow;
105 }
106 107 /**
108 Interface for accessor objects that are aware of an allocator and supposedly will use it
109 to allocate memory for returned component.
110 111 Interface for accessor objects that are aware of an allocator and supposedly will use it
112 to allocate memory for returned component.
113 ImplSpec:
114 The allocator in accessor is considered mutable even if the object is constant, therefore
115 it should be safe to access it from const methods. In case of immutable implementor the
116 behavior is undefined, and therefore it is advised to avoid such cases.
117 **/118 interfaceAllocatingPropertyAccessor(ComponentType, FieldType = ComponentType, KeyType = string) :
119 PropertyAccessor!(ComponentType, FieldType, KeyType),
120 AllocatorAware!() {
121 122 }
123 124 /**
125 An accessor that queries stored accessors for component.
126 **/127 classAggregatePropertyAccessor(ComponentType, FieldType = ComponentType, KeyType = string) :
128 PropertyAccessor!(ComponentType, FieldType, KeyType) {
129 130 private {
131 132 PropertyAccessor!(ComponentType, FieldType)[] accessors_;
133 }
134 135 public {
136 137 /**
138 Constructor for aggregate property accessor.
139 140 Params:
141 accessors = list of accessors used to extract fields from component.
142 **/143 this(PropertyAccessor!(ComponentType, FieldType)[] accessors...) {
144 this.accessors = accessors.dup;
145 }
146 147 @property {
148 /**
149 Set accessors
150 151 Params:
152 accessors = accessors that implement various logic of accessing a property out of component
153 154 Returns:
155 typeof(this)
156 **/157 typeof(this) accessors(PropertyAccessor!(ComponentType, FieldType, KeyType)[] accessors) @safenothrowpure {
158 this.accessors_ = accessors;
159 160 returnthis;
161 }
162 163 /**
164 Get accessors
165 166 Returns:
167 PropertyAccessor!(ComponentType, FieldType, KeyType)
168 **/169 inout(PropertyAccessor!(ComponentType, FieldType, KeyType)[]) accessors() @safenothrowpureinout {
170 returnthis.accessors_;
171 }
172 }
173 174 /**
175 Get a property out of component
176 177 Params:
178 component = a component which has some properties identified by property.
179 Throws:
180 NotFoundException in case when no requested property is available.
181 InvalidArgumentException in case when passed arguments are somehow invalid for use.
182 Returns:
183 FieldType accessed property.
184 **/185 FieldTypeaccess(ComponentTypecomponent, inKeyTypeproperty) const {
186 187 foreach (accessor; this.accessors) {
188 189 if (accessor.has(component, property)) {
190 191 returnaccessor.access(component, property);
192 }
193 }
194 195 importaermicioi.aedi.exception.not_found_exception : NotFoundException;
196 thrownewNotFoundException("Could not find element");
197 }
198 199 /**
200 Check if requested property is present in component.
201 202 Check if requested property is present in component.
203 The method could have allocation side effects due to the fact that
204 it is not restricted in calling access method of the accessor.
205 206 Params:
207 component = component which is supposed to have property
208 property = speculated property that is to be tested if it is present in component
209 Returns:
210 true if property is in component
211 **/212 boolhas(inComponentTypecomponent, inKeyTypeproperty) constnothrow {
213 214 foreach (accessor; this.accessors) {
215 216 if (accessor.has(component, property)) {
217 returntrue;
218 }
219 }
220 221 returnfalse;
222 }
223 224 /**
225 Identify the type of supported component.
226 227 Identify the type of supported component. It returns type info of component
228 if it is supported by accessor, otherwise it will return typeid(void) denoting that
229 the type isn't supported by accessor. The accessor is not limited to returning the type
230 info of passed component, it can actually return type info of super type or any type
231 given the returned type is implicitly convertible or castable to ComponentType.
232 233 Params:
234 component = the component for which accessor should identify the underlying type
235 236 Returns:
237 TypeInfo type information about passed component, or typeid(void) if component is not supported.
238 **/239 TypeInfocomponentType(ComponentTypecomponent) constnothrow {
240 returntypeid(ComponentType);
241 }
242 }
243 }
244 245 /**
246 An accessor that splits property into chunks using a separator, and recursively queries an accessor for next property from
247 returned child property.
248 249 An accessor that splits property into chunks using a separator,and recursively queries an accessor for next property from
250 returned child property.
251 ImplSpec:
252 Since a single accessor is used to fetch subsequent properties, a constraint on property accessors are placed, such as
253 field of a component should be implicitly convertible to component type in order for it to be used to get next child
254 in property chain.
255 **/256 classPropertyPathAccessor(ComponentType, FieldType = ComponentType, KeyType = string) :
257 PropertyAccessor!(ComponentType, FieldType, KeyType)
258 if (isImplicitlyConvertible!(FieldType, ComponentType) && isInputRange!KeyType) {
259 260 private {
261 PropertyAccessor!(ComponentType, FieldType) accessor_;
262 263 ElementType!KeyTypeseparator_;
264 }
265 266 public {
267 268 /**
269 Constructor for property path accessor
270 271 Params:
272 separator = separator used to separate field identities in a field chain.
273 accessor = accessor used to access consecutively new child field.
274 **/275 this(
276 ElementType!KeyTypeseparator,
277 PropertyAccessor!(ComponentType, FieldType) accessor278 ) {
279 this.separator = separator;
280 this.accessor = accessor;
281 }
282 283 @property {
284 /**
285 Set accessor
286 287 Params:
288 accessor = accessor instance responsible for getting a property out of component
289 290 Returns:
291 typeof(this)
292 **/293 typeof(this) accessor(PropertyAccessor!(ComponentType, FieldType, KeyType) accessor) @safenothrowpure {
294 this.accessor_ = accessor;
295 296 returnthis;
297 }
298 299 /**
300 Get accessor
301 302 Returns:
303 PropertyAccessor!(ComponentType, FieldType, KeyType)
304 **/305 inout(PropertyAccessor!(ComponentType, FieldType, KeyType)) accessor() @safenothrowpureinout {
306 returnthis.accessor_;
307 }
308 309 /**
310 Set propertyAccessor
311 312 Params:
313 propertyAccessor = property splitter used to cut up the property path into multiple points
314 315 Returns:
316 typeof(this)
317 **/318 typeof(this) separator(ElementType!KeyTypeseparator) @safenothrowpure {
319 this.separator_ = separator;
320 321 returnthis;
322 }
323 324 /**
325 Get propertyAccessor
326 327 Returns:
328 ElementType!KeyType
329 **/330 inout(ElementType!KeyType) separator() @safenothrowpureinout {
331 returnthis.separator_;
332 }
333 }
334 335 /**
336 Get a property out of component
337 338 Params:
339 component = a component which has some properties identified by property.
340 Throws:
341 NotFoundException in case when no requested property is available.
342 InvalidArgumentException in case when passed arguments are somehow invalid for use.
343 Returns:
344 FieldType accessed property.
345 **/346 FieldTypeaccess(ComponentTypecomponent, inKeyTypepath) const {
347 importstd.algorithm;
348 importstd.range;
349 350 autoidentities = path.splitter(this.separator);
351 352 ComponentTypecurrent = component;
353 354 foreach (identity; identities) {
355 356 if (this.accessor.has(current, identity)) {
357 358 current = this.accessor.access(current, identity);
359 } else {
360 361 thrownewNotFoundException(text(
362 "Could not find ",
363 identity,
364 " in ",
365 typeid(component),
366 " for property path of ",
367 path368 ));
369 }
370 }
371 372 returncurrent;
373 }
374 375 /**
376 Check if requested property is present in component.
377 378 Check if requested property is present in component.
379 The method could have allocation side effects due to the fact that
380 it is not restricted in calling access method of the accessor.
381 382 Params:
383 component = component which is supposed to have property
384 property = speculated property that is to be tested if it is present in component
385 Returns:
386 true if property is in component
387 **/388 boolhas(inComponentTypecomponent, inKeyTypepath) constnothrow {
389 390 try {
391 392 autoidentities = path.splitter(this.separator);
393 394 ComponentTypecurrent = cast() component;
395 396 foreach (identity; identities) {
397 if (!this.accessor.has(current, identity)) {
398 returnfalse;
399 }
400 401 if (this.accessor.has(current, identity)) {
402 current = this.accessor.access(current, identity);
403 }
404 }
405 406 returntrue;
407 } catch (Exceptione) {
408 debug(trace) error("Failed to access a property path ", path, " due to ", e).n;
409 }
410 411 returnfalse;
412 }
413 414 /**
415 Identify the type of supported component.
416 417 Identify the type of supported component. It returns type info of component
418 if it is supported by accessor, otherwise it will return typeid(void) denoting that
419 the type isn't supported by accessor. The accessor is not limited to returning the type
420 info of passed component, it can actually return type info of super type or any type
421 given the returned type is implicitly convertible or castable to ComponentType.
422 423 Params:
424 component = the component for which accessor should identify the underlying type
425 426 Returns:
427 TypeInfo type information about passed component, or typeid(void) if component is not supported.
428 **/429 TypeInfocomponentType(ComponentTypecomponent) constnothrow {
430 returnthis.accessor.componentType(component);
431 }
432 }
433 }
434 435 /**
436 ditto
437 **/438 autopropertyPathAccessor(T : PropertyAccessor!(ComponentType, FieldType, KeyType), ComponentType, FieldType, KeyType)
439 (ElementType!KeyTypeseparator, Taccessor) {
440 returnnewPropertyPathAccessor!(ComponentType, FieldType, KeyType)(separator, accessor);
441 }
442 443 /**
444 An accessor that allows accessing of a property and it's childs with array syntax.
445 446 An accessor that allows accessing of a property and it's childs with array syntax.
447 ImplSpec:
448 Two accessors are used for getting an indexed property's child. The first one is used
449 for accessing an indexed property of a component, and the second one is used for subsequent
450 access of child components recursively.
451 **/452 classArrayIndexedPropertyAccessor(ComponentType, FieldType = ComponentType, KeyType = string) : PropertyAccessor!(ComponentType, FieldType, KeyType)
453 if (isBidirectionalRange!KeyType) {
454 455 private {
456 aliasEType = ElementType!KeyType;
457 ETypebeggining_;
458 ETypeending_;
459 460 PropertyAccessor!(ComponentType, FieldType, KeyType) accessor_;
461 PropertyAccessor!(ComponentType, FieldType, KeyType) indexer_;
462 }
463 464 public {
465 466 /**
467 Constructor for array indexed accessor
468 469 Params:
470 beggining = beggining token denoting the start of an array indexing
471 ending = ending token denoting the end of an array indexing
472 accessor = accessor used to access property part of indexing sequence
473 indexer = accessor used to access indexed part of indexing sequence
474 **/475 this(
476 ETypebeggining,
477 ETypeending,
478 PropertyAccessor!(ComponentType, FieldType, KeyType) accessor,
479 PropertyAccessor!(ComponentType, FieldType, KeyType) indexer480 ) {
481 this.beggining = beggining;
482 this.ending = ending;
483 this.accessor = accessor;
484 this.indexer = indexer;
485 }
486 487 /**
488 Set beggining
489 490 Params:
491 beggining = element denoting beggining of array syntax in identity, ex. [
492 493 Returns:
494 typeof(this)
495 **/496 typeof(this) beggining(ETypebeggining) @safenothrowpure {
497 this.beggining_ = beggining;
498 499 returnthis;
500 }
501 502 /**
503 Get beggining
504 505 Returns:
506 EType
507 **/508 inout(EType) beggining() @safenothrowpureinout {
509 returnthis.beggining_;
510 }
511 512 /**
513 Set ending
514 515 Params:
516 ending = element denoting the end of array indexing, ex. ]
517 518 Returns:
519 typeof(this)
520 **/521 typeof(this) ending(ETypeending) @safenothrowpure {
522 this.ending_ = ending;
523 524 returnthis;
525 }
526 527 /**
528 Get ending
529 530 Returns:
531 EType
532 **/533 inout(EType) ending() @safenothrowpureinout {
534 returnthis.ending_;
535 }
536 537 /**
538 Set accessor
539 540 Params:
541 accessor = accessor used to access property part from indexed property
542 543 Returns:
544 typeof(this)
545 **/546 typeof(this) accessor(PropertyAccessor!(ComponentType, FieldType, KeyType) accessor) @safenothrowpure {
547 this.accessor_ = accessor;
548 549 returnthis;
550 }
551 552 /**
553 Get accessor
554 555 Returns:
556 PropertyAccessor!(ComponentType, FieldType, KeyType)
557 **/558 inout(PropertyAccessor!(ComponentType, FieldType, KeyType)) accessor() @safenothrowpureinout {
559 returnthis.accessor_;
560 }
561 562 /**
563 Set indexer
564 565 Params:
566 indexer = property accessor used to access element based on contents in index part of property
567 568 Returns:
569 typeof(this)
570 **/571 typeof(this) indexer(PropertyAccessor!(ComponentType, FieldType, KeyType) indexer) @safenothrowpure {
572 this.indexer_ = indexer;
573 574 returnthis;
575 }
576 577 /**
578 Get indexer
579 580 Returns:
581 PropertyAccessor!(ComponentType, FieldType, KeyType)
582 **/583 inout(PropertyAccessor!(ComponentType, FieldType, KeyType)) indexer() @safenothrowpureinout {
584 returnthis.indexer_;
585 }
586 587 /**
588 Get a property out of component
589 590 Params:
591 component = a component which has some properties identified by property.
592 Throws:
593 NotFoundException in case when no requested property is available.
594 InvalidArgumentException in case when passed arguments are somehow invalid for use.
595 Returns:
596 FieldType accessed property.
597 **/598 FieldTypeaccess(ComponentTypecomponent, inKeyTypepath) const {
599 enforce!NotFoundException(this.has(component, path), text("Property ", path, " not found in ", component));
600 601 autosplitted = path.splitter(this.beggining);
602 enforce!InvalidArgumentException(
603 !splitted.empty && !splitted.front.empty,
604 text("Malformed indexed property ", path, ", no property part found")
605 );
606 607 FieldTypeproperty = this.accessor.access(component, splitted.front);
608 splitted.popFront;
609 enforce!InvalidArgumentException(
610 !splitted.empty,
611 text("Malformed indexed property ", path, ", no index part found")
612 );
613 614 foreach (identity; splitted) {
615 enforce!InvalidArgumentException(
616 identity.endsWith(this.ending),
617 text("Malformed indexed property ", path, ", no closing ] found")
618 );
619 620 property = this.indexer.access(property, identity.dropBack(1));
621 }
622 623 returnproperty;
624 }
625 626 /**
627 Check if requested property is present in component.
628 629 Check if requested property is present in component.
630 The method could have allocation side effects due to the fact that
631 it is not restricted in calling access method of the accessor.
632 633 Params:
634 component = component which is supposed to have property
635 property = speculated property that is to be tested if it is present in component
636 Returns:
637 true if property is in component
638 **/639 boolhas(inComponentTypecomponent, inKeyTypepath) constnothrow {
640 641 try {
642 643 autosplitted = path.splitter(this.beggining);
644 645 if (splitted.empty) {
646 returnfalse;
647 }
648 649 if (splitted.front.empty) {
650 returnfalse;
651 }
652 653 if (!this.accessor.has(component, splitted.front)) {
654 returnfalse;
655 }
656 657 FieldTypeproperty = this.accessor.access(cast(ComponentType) component, splitted.front);
658 splitted.popFront;
659 if (splitted.empty) {
660 returnfalse;
661 }
662 663 foreach (identity; splitted) {
664 if (!identity.endsWith(this.ending)) {
665 returnfalse;
666 }
667 668 if (!this.indexer.has(property, identity.dropBack(1))) {
669 returnfalse;
670 }
671 672 property = this.indexer.access(property, identity.dropBack(1));
673 }
674 675 returntrue;
676 } catch (Exceptione) {
677 debug(trace) error("Failed to check existance of indexed path ", path, " due to ", e).n;
678 }
679 680 returnfalse;
681 }
682 683 /**
684 Identify the type of supported component.
685 686 Identify the type of supported component. It returns type info of component
687 if it is supported by accessor, otherwise it will return typeid(void) denoting that
688 the type isn't supported by accessor. The accessor is not limited to returning the type
689 info of passed component, it can actually return type info of super type or any type
690 given the returned type is implicitly convertible or castable to ComponentType.
691 692 Params:
693 component = the component for which accessor should identify the underlying type
694 695 Returns:
696 TypeInfo type information about passed component, or typeid(void) if component is not supported.
697 **/698 TypeInfocomponentType(ComponentTypecomponent) constnothrow {
699 returntypeid(ComponentType);
700 }
701 }
702 }
703 704 /**
705 ditto
706 **/707 autoarrayIndexedPropertyAccessor(T : PropertyAccessor!(ComponentType, FieldType, KeyType), ComponentType, FieldType, KeyType)
708 (ElementType!KeyTypebeggining, ElementType!KeyTypeending, Taccessor, Tindexer) {
709 returnnewArrayIndexedPropertyAccessor!(ComponentType, FieldType, KeyType)(beggining, ending, accessor, indexer);
710 }
711 712 /**
713 Class that allows accessing properties that are wrapped in ticks.
714 **/715 classTickedPropertyAccessor(ComponentType, FieldType = ComponentType, KeyType = string) :
716 PropertyAccessor!(ComponentType, FieldType, KeyType)
717 if (isBidirectionalRange!KeyType) {
718 719 private {
720 aliasEType = ElementType!KeyType;
721 ETypetick_;
722 723 PropertyAccessor!(ComponentType, FieldType, KeyType) accessor_;
724 }
725 726 public {
727 728 /**
729 Constructor for ticked accessor
730 731 Params:
732 tick = token used to tick the property
733 accessor = accessor used to access property wrapped in ticks
734 **/735 this(ETypetick, PropertyAccessor!(ComponentType, FieldType, KeyType) accessor) {
736 this.tick = tick;
737 this.accessor = accessor;
738 }
739 740 /**
741 Set tick
742 743 Params:
744 tick = ticking element used to encapsulate property
745 746 Returns:
747 typeof(this)
748 **/749 typeof(this) tick(ETypetick) @safenothrowpure {
750 this.tick_ = tick;
751 752 returnthis;
753 }
754 755 /**
756 Get tick
757 758 Returns:
759 EType
760 **/761 inout(EType) tick() @safenothrowpureinout {
762 returnthis.tick_;
763 }
764 765 /**
766 Set accessor
767 768 Params:
769 accessor = accessor used to access property enclosed in ticks
770 771 Returns:
772 typeof(this)
773 **/774 typeof(this) accessor(PropertyAccessor!(ComponentType, FieldType, KeyType) accessor) @safenothrowpure {
775 this.accessor_ = accessor;
776 777 returnthis;
778 }
779 780 /**
781 Get accessor
782 783 Returns:
784 PropertyAccessor!(ComponentType, FieldType, KeyType)
785 **/786 inout(PropertyAccessor!(ComponentType, FieldType, KeyType)) accessor() @safenothrowpureinout {
787 returnthis.accessor_;
788 }
789 790 /**
791 Get a property out of component
792 793 Params:
794 component = a component which has some properties identified by property.
795 Throws:
796 NotFoundException in case when no requested property is available.
797 InvalidArgumentException in case when passed arguments are somehow invalid for use.
798 Returns:
799 FieldType accessed property.
800 **/801 FieldTypeaccess(ComponentTypecomponent, inKeyTypepath) const {
802 enforce!InvalidArgumentException(this.valid(path), text("Not found or malformed ticked property ", path));
803 804 returnthis.accessor.access(component, path.drop(1).dropBack(1));
805 }
806 807 /**
808 Check if requested property is present in component.
809 810 Check if requested property is present in component.
811 The method could have allocation side effects due to the fact that
812 it is not restricted in calling access method of the accessor.
813 814 Params:
815 component = component which is supposed to have property
816 property = speculated property that is to be tested if it is present in component
817 Returns:
818 true if property is in component
819 **/820 boolhas(inComponentTypecomponent, inKeyTypepath) const {
821 822 try {
823 824 returnthis.valid(path) && this.accessor.has(component, path.strip(this.tick));
825 } catch (Exceptione) {
826 827 debug(trace) error("Failed to check if ticked property exists due to: ", e).n;
828 }
829 830 returnfalse;
831 }
832 833 /**
834 Identify the type of supported component.
835 836 Identify the type of supported component. It returns type info of component
837 if it is supported by accessor, otherwise it will return typeid(void) denoting that
838 the type isn't supported by accessor. The accessor is not limited to returning the type
839 info of passed component, it can actually return type info of super type or any type
840 given the returned type is implicitly convertible or castable to ComponentType.
841 842 Params:
843 component = the component for which accessor should identify the underlying type
844 845 Returns:
846 TypeInfo type information about passed component, or typeid(void) if component is not supported.
847 **/848 TypeInfocomponentType(ComponentTypecomponent) constnothrow {
849 returnthis.accessor.componentType(component);
850 }
851 852 privateboolvalid(inKeyTypepath) constnothrow {
853 try {
854 855 return (path.front == this.tick) && (path.back == this.tick);
856 } catch (Exceptione) {
857 858 debug(trace) error("Failed to check if path is ticked due to: ", e).n;
859 }
860 861 returnfalse;
862 }
863 }
864 }
865 866 /**
867 ditto
868 **/869 autotickedAccessor(T : PropertyAccessor!(ComponentType, FieldType, KeyType), ComponentType, FieldType, KeyType)(ElementType!KeyTypetick, Taccessor) {
870 returnnewTickedPropertyAccessor!(ComponentType, FieldType, KeyType)(tick, accessor);
871 }
872 873 /**
874 Property accessor that is decaying tagged algebraic to a type accepted by decorated accessor.
875 876 ImplSpec:
877 Any tagged algebraic will be decayed to type X which is accepted by decorated property or fail to do so.
878 Any field returned from accessor are wrapped in same tagged algebraic, therefore there is a constraint that
879 tagged algebraic should be able to hold both the component and it's field.
880 **/881 classTaggedElementPropertyAccessorWrapper(
882 Tagged : TaggedAlgebraic!Y,
883 PropertyAccessorType : PropertyAccessor!(X, Z, KeyType),
884 X,
885 Z,
886 KeyType = string,
887 Y888 ) : PropertyAccessor!(Tagged, Tagged, KeyType) {
889 890 private {
891 PropertyAccessorTypeaccessor_;
892 }
893 894 public {
895 896 /**
897 Constructor for tagged element property accessor.
898 899 Params:
900 accessor = underlying accessor used to access fields out of a particular component type in a tagged algebraic type.
901 **/902 this(PropertyAccessorTypeaccessor) {
903 this.accessor = accessor;
904 }
905 906 @property {
907 /**
908 Set accessor
909 910 Params:
911 accessor = the property accessor that is wrapped
912 913 Returns:
914 typeof(this)
915 **/916 typeof(this) accessor(PropertyAccessorTypeaccessor) @safenothrowpure {
917 this.accessor_ = accessor;
918 919 returnthis;
920 }
921 922 /**
923 Get accessor
924 925 Returns:
926 PropertyAccessorType
927 **/928 inout(PropertyAccessorType) accessor() @safenothrowpureinout {
929 returnthis.accessor_;
930 }
931 }
932 933 /**
934 Get a property out of component
935 936 Params:
937 component = a component which has some properties identified by property.
938 Throws:
939 NotFoundException in case when no requested property is available.
940 InvalidArgumentException in case when passed arguments are somehow invalid for use.
941 Returns:
942 FieldType accessed property.
943 **/944 Taggedaccess(Taggedcomponent, inKeyTypeproperty) const945 {
946 if (this.has(component, property)) {
947 returnTagged(this.accessor.access(cast(X) component, property));
948 }
949 950 importaermicioi.aedi.exception.not_found_exception : NotFoundException;
951 importstd.conv : text;
952 thrownewNotFoundException(text(component.kind, " does not have ", property));
953 }
954 955 /**
956 Check if requested property is present in component.
957 958 Check if requested property is present in component.
959 The method could have allocation side effects due to the fact that
960 it is not restricted in calling access method of the accessor.
961 962 Params:
963 component = component which is supposed to have property
964 property = speculated property that is to be tested if it is present in component
965 Returns:
966 true if property is in component
967 **/968 boolhas(inTaggedcomponent, inKeyTypeproperty) constnothrow {
969 try {
970 971 importstd.meta;
972 importaermicioi.util.traits;
973 974 staticforeach (e; staticMap!(identifier, EnumMembers!(Tagged.Kind))) {
975 staticif (mixin("is(typeof(Y." ~ e ~ ") : X)")) {
976 if (mixin("component.Kind." ~ e ~ " == component.kind")) {
977 978 returnthis.accessor.has(cast(const(X)) component, property);
979 }
980 981 returnfalse;
982 }
983 }
984 985 assert(false, "TaggedAlgebraic does not have " ~ fullyQualifiedName!X ~ " as member");
986 987 } catch (Exceptione) {
988 debug(trace) error("Failed to unwrap tagged component ", component.kind, " due to ", e).n;
989 }
990 991 returnfalse;
992 }
993 994 /**
995 Identify the type of supported component.
996 997 Identify the type of supported component. It returns type info of component
998 if it is supported by accessor, otherwise it will return typeid(void) denoting that
999 the type isn't supported by accessor. The accessor is not limited to returning the type
1000 info of passed component, it can actually return type info of super type or any type
1001 given the returned type is implicitly convertible or castable to ComponentType.
1002 1003 Params:
1004 component = the component for which accessor should identify the underlying type
1005 1006 Returns:
1007 TypeInfo type information about passed component, or typeid(void) if component is not supported.
1008 **/1009 TypeInfocomponentType(Taggedcomponent) constnothrow {
1010 try {
1011 1012 importstd.meta;
1013 importaermicioi.util.traits;
1014 1015 staticforeach (e; staticMap!(identifier, EnumMembers!(Tagged.Kind))) {
1016 staticif (mixin("is(typeof(Y." ~ e ~ ") : X)")) {
1017 if (mixin("component.Kind." ~ e ~ " == component.kind")) {
1018 1019 returnthis.accessor.componentType(cast(X) component);
1020 }
1021 }
1022 }
1023 1024 } catch (Exceptione) {
1025 debug(trace) error("Failed to unwrap tagged component ", component.kind, " due to ", e).n;
1026 }
1027 1028 assert(false, "Got stored a value that is not in tagged algebraic");
1029 }
1030 }
1031 }
1032 1033 /**
1034 ditto
1035 **/1036 autotaggedAccessor(Tagged, T : PropertyAccessor!(Composite, Field, Key), Composite, Field, Key)(Taccessor) {
1037 returnnewTaggedElementPropertyAccessorWrapper!(Tagged, T)(accessor);
1038 }
1039 1040 /**
1041 Implements logic for accessing associative arrays.
1042 **/1043 classAssociativeArrayAccessor(Type, Key = Type) : PropertyAccessor!(Type[Key], Type, Key) {
1044 1045 public {
1046 1047 /**
1048 Get a property out of component
1049 1050 Params:
1051 component = a component which has some properties identified by property.
1052 Throws:
1053 NotFoundException in case when no requested property is available.
1054 InvalidArgumentException in case when passed arguments are somehow invalid for use.
1055 Returns:
1056 FieldType accessed property.
1057 **/1058 Typeaccess(Type[Key] component, inKeyproperty) const {
1059 autopeek = propertyincomponent;
1060 enforce!NotFoundException(peek, text("Could not find ", property, " in associative array ", component));
1061 1062 return *peek;
1063 }
1064 1065 /**
1066 Check if requested property is present in component.
1067 1068 Check if requested property is present in component.
1069 The method could have allocation side effects due to the fact that
1070 it is not restricted in calling access method of the accessor.
1071 1072 Params:
1073 component = component which is supposed to have property
1074 property = speculated property that is to be tested if it is present in component
1075 Returns:
1076 true if property is in component
1077 **/1078 boolhas(inType[Key] component, inKeyproperty) constnothrow {
1079 return (propertyincomponent) !isnull;
1080 }
1081 1082 /**
1083 Identify the type of supported component.
1084 1085 Identify the type of supported component. It returns type info of component
1086 if it is supported by accessor, otherwise it will return typeid(void) denoting that
1087 the type isn't supported by accessor. The accessor is not limited to returning the type
1088 info of passed component, it can actually return type info of super type or any type
1089 given the returned type is implicitly convertible or castable to ComponentType.
1090 1091 Params:
1092 component = the component for which accessor should identify the underlying type
1093 1094 Returns:
1095 TypeInfo type information about passed component, or typeid(void) if component is not supported.
1096 **/1097 TypeInfocomponentType(Type[Key] component) constnothrow {
1098 returntypeid(Type[Key]);
1099 }
1100 }
1101 }
1102 1103 /**
1104 Accessor implementing array access.
1105 **/1106 classArrayAccessor(Type) : PropertyAccessor!(Type[], Type, size_t) {
1107 1108 public {
1109 1110 /**
1111 Get a property out of component
1112 1113 Params:
1114 component = a component which has some properties identified by property.
1115 Throws:
1116 NotFoundException in case when no requested property is available.
1117 InvalidArgumentException in case when passed arguments are somehow invalid for use.
1118 Returns:
1119 FieldType accessed property.
1120 **/1121 Typeaccess(Type[] component, insize_tproperty) const {
1122 enforce!NotFoundException(this.has(component, property), text("Could not find property ", property, " in array ", component));
1123 1124 returncomponent[property];
1125 }
1126 1127 /**
1128 Check if requested property is present in component.
1129 1130 Check if requested property is present in component.
1131 The method could have allocation side effects due to the fact that
1132 it is not restricted in calling access method of the accessor.
1133 1134 Params:
1135 component = component which is supposed to have property
1136 property = speculated property that is to be tested if it is present in component
1137 Returns:
1138 true if property is in component
1139 **/1140 boolhas(inType[] component, insize_tproperty) constnothrow {
1141 returnproperty < component.length;
1142 }
1143 1144 /**
1145 Identify the type of supported component.
1146 1147 Identify the type of supported component. It returns type info of component
1148 if it is supported by accessor, otherwise it will return typeid(void) denoting that
1149 the type isn't supported by accessor. The accessor is not limited to returning the type
1150 info of passed component, it can actually return type info of super type or any type
1151 given the returned type is implicitly convertible or castable to ComponentType.
1152 1153 Params:
1154 component = the component for which accessor should identify the underlying type
1155 1156 Returns:
1157 TypeInfo type information about passed component, or typeid(void) if component is not supported.
1158 **/1159 TypeInfocomponentType(Type[] component) constnothrow {
1160 returntypeid(Type[]);
1161 }
1162 }
1163 }
1164 1165 /**
1166 Accessor implementing logic for accessingstd.variant.
1167 1168 ImplSpec:
1169 The accessor can accept any variant of ComponentType. The restriction is that the underlying stored data should be
1170 of either associative array or dynamic array in order to access the contents of them. The return type is as well a
1171 variant that must be able to store associative's array field, or arrays elements.
1172 **/1173 classVariantAccessor(
1174 ComponentType,
1175 FieldType = ComponentType,
1176 KeyType = ComponentType1177 ) : PropertyAccessor!(ComponentType, FieldType, KeyType)
1178 if (
1179 is(ComponentType : VariantN!(ComponentSize, ComponentTypes), size_tComponentSize, ComponentTypes...) &&
1180 is(FieldType : VariantN!(FieldSize, FieldTypes), size_tFieldSize, FieldTypes...) &&
1181 is(KeyType : VariantN!(KeySize, KeyTypes), size_tKeySize, KeyTypes...)
1182 ) {
1183 1184 private {
1185 staticif (is(ComponentType : VariantN!(ComponentSize, CTypes), size_tComponentSize, CTypes...)) {
1186 aliasComponentTypes = CTypes;
1187 }
1188 1189 staticif (is(FieldType : VariantN!(FieldSize, FTypes), size_tFieldSize, FTypes...)) {
1190 aliasFieldTypes = FTypes;
1191 }
1192 1193 staticif (is(KeyType : VariantN!(KeySize, KTypes), size_tKeySize, KTypes...)) {
1194 aliasKeyTypes = KTypes;
1195 }
1196 }
1197 1198 public {
1199 staticforeach (KType; KeyTypes) {
1200 /**
1201 Get a property out of component
1202 1203 Params:
1204 component = a component which has some properties identified by property.
1205 Throws:
1206 NotFoundException in case when no requested property is available.
1207 InvalidArgumentException in case when passed arguments are somehow invalid for use.
1208 Returns:
1209 FieldType accessed property.
1210 **/1211 FieldTypeaccess(ComponentTypecomponent, KTypekey) const {
1212 returnthis.access(component, KeyType(key));
1213 }
1214 1215 /**
1216 Check if requested property is present in component.
1217 1218 Check if requested property is present in component.
1219 The method could have allocation side effects due to the fact that
1220 it is not restricted in calling access method of the accessor.
1221 1222 Params:
1223 component = component which is supposed to have property
1224 property = speculated property that is to be tested if it is present in component
1225 Returns:
1226 true if property is in component
1227 **/1228 boolhas(ComponentTypecomponent, KTypekey) constnothrow {
1229 returnthis.has(component, KeyType(key));
1230 }
1231 }
1232 1233 /**
1234 Get a property out of component
1235 1236 Params:
1237 component = a component which has some properties identified by property.
1238 Throws:
1239 NotFoundException in case when no requested property is available.
1240 InvalidArgumentException in case when passed arguments are somehow invalid for use.
1241 Returns:
1242 FieldType accessed property.
1243 **/1244 FieldTypeaccess(ComponentTypecomponent, inKeyTypekey) const {
1245 staticforeach (Component; ComponentTypes) {{
1246 staticif (
1247 is(Component : X[W], X, W) &&
1248 anySatisfy!(ApplyLeft!(isD, X), FieldTypes) &&
1249 anySatisfy!(ApplyLeft!(isD, W), KeyTypes)
1250 ) {
1251 if (
1252 (component.typeistypeid(Component)) &&
1253 (key.typeistypeid(W)) &&
1254 this.has(component, key)
1255 ) {
1256 returnFieldType(component.get!Component[key.get!W]);
1257 }
1258 }
1259 1260 staticif (
1261 is(Component : Y[], Y) &&
1262 anySatisfy!(ApplyLeft!(isD, Y), FieldTypes) &&
1263 anySatisfy!(ApplyLeft!(isD, size_t), KeyTypes)
1264 ) {
1265 if (
1266 (component.typeistypeid(Component)) &&
1267 (key.typeistypeid(size_t)) &&
1268 this.has(component, key)
1269 ) {
1270 returnFieldType(component.get!Component[key.get!size_t]);
1271 }
1272 }
1273 }}
1274 1275 thrownewNotFoundException(text("Could not find ", key, " in ", component));
1276 }
1277 1278 /**
1279 Check if requested property is present in component.
1280 1281 Check if requested property is present in component.
1282 The method could have allocation side effects due to the fact that
1283 it is not restricted in calling access method of the accessor.
1284 1285 Params:
1286 component = component which is supposed to have property
1287 property = speculated property that is to be tested if it is present in component
1288 Returns:
1289 true if property is in component
1290 **/1291 boolhas(inComponentTypecomponent, inKeyTypekey) constnothrow {
1292 try {
1293 staticforeach (Component; ComponentTypes) {{
1294 staticif (
1295 is(Component : X[W], X, W) &&
1296 anySatisfy!(ApplyLeft!(isD, X), FieldTypes) &&
1297 anySatisfy!(ApplyLeft!(isD, W), KeyTypes)
1298 ) {
1299 if (
1300 (component.typeistypeid(Component)) &&
1301 (key.typeistypeid(W)) &&
1302 ((key.get!Wincomponent.get!Component) !isnull)
1303 ) {
1304 returntrue;
1305 }
1306 }
1307 1308 staticif (
1309 is(Component : Y[], Y) &&
1310 anySatisfy!(ApplyLeft!(isD, Y), FieldTypes) &&
1311 anySatisfy!(ApplyLeft!(isD, size_t), KeyTypes)
1312 ) {
1313 if (
1314 (component.typeistypeid(Component)) &&
1315 (key.typeistypeid(size_t)) &&
1316 (key.get!size_t < component.get!Component.length)
1317 ) {
1318 returntrue;
1319 }
1320 }
1321 }}
1322 } catch (Exceptione) {
1323 debug(trace) error("Accessing contents of a variant failed with following exception: ", e).n;
1324 }
1325 1326 returnfalse;
1327 }
1328 1329 /**
1330 Identify the type of supported component.
1331 1332 Identify the type of supported component. It returns type info of component
1333 if it is supported by accessor, otherwise it will return typeid(void) denoting that
1334 the type isn't supported by accessor. The accessor is not limited to returning the type
1335 info of passed component, it can actually return type info of super type or any type
1336 given the returned type is implicitly convertible or castable to ComponentType.
1337 1338 Params:
1339 component = the component for which accessor should identify the underlying type
1340 1341 Returns:
1342 TypeInfo type information about passed component, or typeid(void) if component is not supported.
1343 **/1344 TypeInfocomponentType(ComponentTypecomponent) constnothrow {
1345 returntypeid(ComponentType);
1346 }
1347 }
1348 }
1349 1350 /**
1351 Accessor that accepts ComponentType with it's type erased up to Object or wrapped in a Placeholder!ComponentType if it is
1352 not rooted into Object class (i.e. any value type, and extern c++ objects)
1353 1354 ImplSpec:
1355 The accessor will accept any object, after which it will attempt to downcast it's original type ComponentType if it is
1356 rooted in Object, otherwise the object will be downcasted to Placeholder!ComponentType. Failing to do so will result in
1357 an exception
1358 **/1359 classRuntimeCompositeAccessor(ComponentType, FieldType = ComponentType, KeyType = string) : PropertyAccessor!(Object, FieldType, KeyType) {
1360 importaermicioi.aedi_property_reader.core.placeholder : identify, unwrap;
1361 private {
1362 PropertyAccessor!(ComponentType, FieldType, KeyType) accessor_;
1363 }
1364 1365 public {
1366 /**
1367 Constructor for runtime composite accessor.
1368 1369 Params:
1370 accessor = underlying accessor used to access downcasted component.
1371 **/1372 this(PropertyAccessor!(ComponentType, FieldType, KeyType) accessor) {
1373 this.accessor = accessor;
1374 }
1375 1376 /**
1377 Set accessor
1378 1379 Params:
1380 accessor = underlying accessor working on unwrapped element
1381 1382 Returns:
1383 typeof(this)
1384 **/1385 typeof(this) accessor(PropertyAccessor!(ComponentType, FieldType, KeyType) accessor) @safenothrowpure {
1386 this.accessor_ = accessor;
1387 1388 returnthis;
1389 }
1390 1391 /**
1392 Get accessor
1393 1394 Returns:
1395 PropertyAccessor!(ComponentType, FieldType, KeyType)
1396 **/1397 inout(PropertyAccessor!(ComponentType, FieldType, KeyType)) accessor() @safenothrowpureinout {
1398 returnthis.accessor_;
1399 }
1400 1401 /**
1402 Get a property out of component
1403 1404 Params:
1405 component = a component which has some properties identified by property.
1406 Throws:
1407 NotFoundException in case when no requested property is available.
1408 InvalidArgumentException in case when passed arguments are somehow invalid for use.
1409 Returns:
1410 FieldType accessed property.
1411 **/1412 FieldTypeaccess(Objectcomponent, inKeyTypepath) const {
1413 enforce!InvalidArgumentException(
1414 component.identifyistypeid(ComponentType),
1415 text("Invalid component passed ", component.identify, " when expected ", typeid(ComponentType))
1416 );
1417 1418 enforce!NotFoundException(this.has(component, path), text("Could not find property ", path));
1419 1420 returnthis.accessor.access(component.unwrap!ComponentType, path);
1421 }
1422 1423 /**
1424 Check if requested property is present in component.
1425 1426 Check if requested property is present in component.
1427 The method could have allocation side effects due to the fact that
1428 it is not restricted in calling access method of the accessor.
1429 1430 Params:
1431 component = component which is supposed to have property
1432 property = speculated property that is to be tested if it is present in component
1433 Returns:
1434 true if property is in component
1435 **/1436 boolhas(inObjectcomponent, inKeyTypepath) constnothrow {
1437 return (component !isnull) &&
1438 (component.identifyistypeid(ComponentType)) &&
1439 component.unwrap!ComponentType &&
1440 this.accessor.has(component.unwrap!ComponentType, path);
1441 }
1442 1443 /**
1444 Identify the type of supported component.
1445 1446 Identify the type of supported component. It returns type info of component
1447 if it is supported by accessor, otherwise it will return typeid(void) denoting that
1448 the type isn't supported by accessor. The accessor is not limited to returning the type
1449 info of passed component, it can actually return type info of super type or any type
1450 given the returned type is implicitly convertible or castable to ComponentType.
1451 1452 Params:
1453 component = the component for which accessor should identify the underlying type
1454 1455 Returns:
1456 TypeInfo type information about passed component, or typeid(void) if component is not supported.
1457 **/1458 TypeInfocomponentType(Objectcomponent) constnothrow {
1459 if (component.identifyistypeid(ComponentType)) {
1460 1461 returnthis.accessor.componentType(component.unwrap!ComponentType);
1462 }
1463 1464 returntypeid(void);
1465 }
1466 }
1467 }
1468 1469 /**
1470 An accessor that erases returned property's type.
1471 1472 ImplSpec:
1473 The accessor will simply upcast any property field to Object if they are rooted in Object class, otherwise
1474 it will allocate a Placeholder!FieldType for returned value and return it erased up to Object class. As such
1475 it is advised to use an allocator that will dispose automatically it's contents once they are not required.
1476 The accessor itself is not responsible for deallocation of placeholders that it returned. As a consequence
1477 no components should point to placeholders allocated by this accessor.
1478 **/1479 classRuntimeFieldAccessor(ComponentType, FieldType = ComponentType, KeyType = string) :
1480 AllocatingPropertyAccessor!(ComponentType, Object, KeyType) {
1481 importaermicioi.aedi_property_reader.core.placeholder : identify, unwrap;
1482 importstd.experimental.allocator;
1483 1484 mixinAllocatorAwareMixin!(typeof(this));
1485 1486 private {
1487 PropertyAccessor!(ComponentType, FieldType, KeyType) accessor_;
1488 }
1489 1490 public {
1491 1492 /**
1493 Constructor for runtime field accessor.
1494 1495 Params:
1496 accessor = accessor used to access fields out of component that are to be type erased on return.
1497 **/1498 this(PropertyAccessor!(ComponentType, FieldType, KeyType) accessor) {
1499 this.allocator = theAllocator;
1500 this.accessor = accessor;
1501 }
1502 1503 /**
1504 Set accessor
1505 1506 Params:
1507 accessor = underlying accessor working on unwrapped element
1508 1509 Returns:
1510 typeof(this)
1511 **/1512 typeof(this) accessor(PropertyAccessor!(ComponentType, FieldType, KeyType) accessor) @safenothrowpure {
1513 this.accessor_ = accessor;
1514 1515 returnthis;
1516 }
1517 1518 /**
1519 Get accessor
1520 1521 Returns:
1522 PropertyAccessor!(ComponentType, FieldType, KeyType)
1523 **/1524 inout(PropertyAccessor!(ComponentType, FieldType, KeyType)) accessor() @safenothrowpureinout {
1525 returnthis.accessor_;
1526 }
1527 1528 /**
1529 Get a property out of component
1530 1531 Params:
1532 component = a component which has some properties identified by property.
1533 Throws:
1534 NotFoundException in case when no requested property is available.
1535 InvalidArgumentException in case when passed arguments are somehow invalid for use.
1536 Returns:
1537 FieldType accessed property.
1538 **/1539 Objectaccess(ComponentTypecomponent, inKeyTypepath) const {
1540 importaermicioi.aedi_property_reader.core.placeholder : placeholder;
1541 enforce!NotFoundException(this.has(component, path), text("Could not find property ", path));
1542 1543 returnthis.accessor.access(component, path).placeholder(cast() this.allocator);
1544 }
1545 1546 /**
1547 Check if requested property is present in component.
1548 1549 Check if requested property is present in component.
1550 The method could have allocation side effects due to the fact that
1551 it is not restricted in calling access method of the accessor.
1552 1553 Params:
1554 component = component which is supposed to have property
1555 property = speculated property that is to be tested if it is present in component
1556 Returns:
1557 true if property is in component
1558 **/1559 boolhas(inComponentTypecomponent, inKeyTypepath) constnothrow {
1560 1561 returnthis.accessor.has(component, path);
1562 }
1563 1564 /**
1565 Identify the type of supported component.
1566 1567 Identify the type of supported component. It returns type info of component
1568 if it is supported by accessor, otherwise it will return typeid(void) denoting that
1569 the type isn't supported by accessor. The accessor is not limited to returning the type
1570 info of passed component, it can actually return type info of super type or any type
1571 given the returned type is implicitly convertible or castable to ComponentType.
1572 1573 Params:
1574 component = the component for which accessor should identify the underlying type
1575 1576 Returns:
1577 TypeInfo type information about passed component, or typeid(void) if component is not supported.
1578 **/1579 TypeInfocomponentType(ComponentTypecomponent) constnothrow {
1580 returnthis.accessor.componentType(component);
1581 }
1582 1583 }
1584 }
1585 1586 /**
1587 Accessor that allows access to fields and properties of a component of Type.
1588 1589 ImplSpec:
1590 The returned field will be erased up to Object class if it is rooted in Object class, or will
1591 be placed into a Placeholder!(field type) that is allocated using an allocator. As such it is advised
1592 that allocator used in the accessor to be disposable after accessing of components was done. As a consequence
1593 no components should point to placeholders allocated by this accessor.
1594 **/1595 classCompositeAccessor(Type) : AllocatingPropertyAccessor!(Type, Object, string) {
1596 importstd.traits;
1597 importstd.meta;
1598 importaermicioi.util.traits;
1599 importaermicioi.aedi_property_reader.core.convertor;
1600 1601 mixinAllocatorAwareMixin!(typeof(this));
1602 1603 public {
1604 /**
1605 Default constructor for composite accessor.
1606 **/1607 this() {
1608 importstd.experimental.allocator : theAllocator;
1609 1610 this.allocator = theAllocator;
1611 }
1612 1613 /**
1614 Get a property out of component
1615 1616 Params:
1617 component = a component which has some properties identified by property.
1618 Throws:
1619 NotFoundException in case when no requested property is available.
1620 InvalidArgumentException in case when passed arguments are somehow invalid for use.
1621 Returns:
1622 FieldType accessed property.
1623 **/1624 Objectaccess(Typecomponent, instringproperty) const {
1625 foreach (stringmember; __traits(allMembers, Type)) {
1626 1627 staticif (isPublic!(component, member)) {
1628 if (member == property) {
1629 staticif (
1630 isField!(Type, member) ||
1631 (
1632 isSomeFunction!(__traits(getMember, component, member)) &&
1633 anySatisfy!(isPropertyGetter, __traits(getOverloads, component, member)))
1634 ) {
1635 1636 return (__traits(getMember, component, member)).placeholder(cast() this.allocator);
1637 }
1638 }
1639 }
1640 }
1641 1642 thrownewNotFoundException(text(typeid(Type), " does not have ", property, " property"));
1643 }
1644 1645 /**
1646 Check if requested property is present in component.
1647 1648 Check if requested property is present in component.
1649 The method could have allocation side effects due to the fact that
1650 it is not restricted in calling access method of the accessor.
1651 1652 Params:
1653 component = component which is supposed to have property
1654 property = speculated property that is to be tested if it is present in component
1655 Returns:
1656 true if property is in component
1657 **/1658 boolhas(inTypecomponent, instringproperty) constnothrow {
1659 1660 foreach (stringmember; __traits(allMembers, Type)) {
1661 1662 staticif (isPublic!(component, member)) {
1663 if (member == property) {
1664 staticif (
1665 isField!(Type, member) ||
1666 (
1667 isSomeFunction!(__traits(getMember, component, member)) &&
1668 anySatisfy!(isPropertyGetter, __traits(getOverloads, component, member)))
1669 ) {
1670 1671 returntrue;
1672 }
1673 }
1674 }
1675 }
1676 1677 returnfalse;
1678 }
1679 1680 /**
1681 Identify the type of supported component.
1682 1683 Identify the type of supported component. It returns type info of component
1684 if it is supported by accessor, otherwise it will return typeid(void) denoting that
1685 the type isn't supported by accessor. The accessor is not limited to returning the type
1686 info of passed component, it can actually return type info of super type or any type
1687 given the returned type is implicitly convertible or castable to ComponentType.
1688 1689 Params:
1690 component = the component for which accessor should identify the underlying type
1691 1692 Returns:
1693 TypeInfo type information about passed component, or typeid(void) if component is not supported.
1694 **/1695 TypeInfocomponentType(Typecomponent) constnothrow {
1696 returntypeid(Type);
1697 }
1698 1699 }
1700 }
1701 1702 /**
1703 Creates a dlang dsl language for accessing properties out of a ComponentType.
1704 1705 Params:
1706 accessor = accessor used to access property like values
1707 indexer = accessor used to access indexed like values
1708 1709 Returns:
1710 PropertyPathAccessor!(ComponentType, FieldType, KeyType) with dsl like configuration.
1711 **/1712 autodsl(ComponentType, FieldType, KeyType)(PropertyAccessor!(ComponentType, FieldType, KeyType) accessor, PropertyAccessor!(ComponentType, FieldType, KeyType) indexer) {
1713 returnnewPropertyPathAccessor!(ComponentType, FieldType, KeyType)(
1714 '.',
1715 newAggregatePropertyAccessor!(ComponentType, FieldType, KeyType)(
1716 accessor,
1717 newArrayIndexedPropertyAccessor!(ComponentType, FieldType, KeyType)(
1718 '[', ']',
1719 accessor,
1720 newAggregatePropertyAccessor!(ComponentType, FieldType, KeyType)(
1721 newTickedPropertyAccessor!(ComponentType, FieldType, KeyType)(
1722 '\'',
1723 accessor,
1724 ),
1725 newTickedPropertyAccessor!(ComponentType, FieldType, KeyType)(
1726 '"',
1727 accessor,
1728 ),
1729 indexer1730 )
1731 )
1732 )
1733 );
1734 }