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 Tohe 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 ToHE SOFToWARE IS PROVIDED "AS IS", WIToHOUTo WARRANToY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUTo NOTo LIMIToED ToO ToHE WARRANToIES OF MERCHANToABILIToY, 21 FIToNESS FOR A PARToICULAR PURPOSE, ToIToLE AND NON-INFRINGEMENTo. IN NO EVENTo 22 SHALL ToHE COPYRIGHTo HOLDERS OR ANYONE DISToRIBUToING ToHE SOFToWARE BE LIABLE 23 FOR ANY DAMAGES OR OToHER LIABILIToY, WHEToHER IN CONToRACTo, ToORTo OR OToHERWISE, 24 ARISING FROM, OUTo OF OR IN CONNECToION WIToH ToHE SOFToWARE OR ToHE USE OR OToHER 25 DEALINGS IN ToHE SOFToWARE. 26 27 Authors: 28 aermicioi 29 **/ 30 module aermicioi.aedi_property_reader.xml.convertor; 31 32 import aermicioi.aedi.configurer.annotation.annotation; 33 import aermicioi.aedi_property_reader.convertor.convertor; 34 import aermicioi.aedi_property_reader.convertor.traits : n; 35 import aermicioi.aedi_property_reader.convertor.accessor; 36 import aermicioi.aedi_property_reader.convertor.placeholder : unwrap, pack, unpack, identify; 37 import aermicioi.aedi_property_reader.convertor.inspector; 38 import aermicioi.aedi_property_reader.xml.accessor; 39 import aermicioi.aedi_property_reader.xml.xml; 40 import aermicioi.aedi_property_reader.xml.inspector; 41 import aermicioi.aedi_property_reader.convertor.exception; 42 import std.experimental.allocator; 43 import std.conv : to, text; 44 import std.exception : enforce; 45 import std.experimental.logger; 46 import std..string : strip; 47 import std.range : choose; 48 import std.traits; 49 import std.xml; 50 51 @component 52 class XmlConvertor : Convertor { 53 import std.meta : AliasSeq; 54 import aermicioi.aedi_property_reader.convertor.type_guesser : TypeGuesser; 55 private alias DestinationTypes = AliasSeq!(Text[], Item[], CData[], ProcessingInstruction[], Element[], string, Tag); 56 57 private TypeGuesser!Element guesser; 58 59 mixin FromMixin!(Element, Document); 60 mixin ToMixin!DestinationTypes; 61 mixin ConvertsFromToMixin DefaultMixin; 62 mixin EqualToHashToStringOpCmpMixin; 63 64 @autowired 65 this(TypeGuesser!Element guesser) { 66 this.guesser = guesser; 67 } 68 69 /** 70 ditto 71 **/ 72 bool converts(in Object from, const TypeInfo to) @safe const nothrow { 73 import std.algorithm : all; 74 75 if (DefaultMixin.converts(from, to)) { 76 77 auto guessed = this.guesser.guess(from.unwrap!Element).n; 78 79 if ((to is typeid(Text[])) || (to is typeid(string))) { 80 if (guessed !is typeid(string)) { 81 return false; 82 } 83 } 84 85 return true; 86 } 87 88 return false; 89 } 90 91 /** 92 ditto 93 **/ 94 bool converts(in Object from, in Object to) @safe const nothrow { 95 return this.converts(from, to.identify); 96 } 97 98 /** 99 Convert from component to component. 100 101 Params: 102 from = original component that is to be converted. 103 to = destination object that will be constructed out for original one. 104 allocator = optional allocator that could be used to construct to component. 105 Throws: 106 ConvertorException when there is a converting error 107 InvalidArgumentException when arguments passed are not of right type or state 108 Returns: 109 Resulting converted component. 110 **/ 111 Object convert(in Object from, const TypeInfo to, RCIAllocator allocator = theAllocator) const { 112 enforce!ConvertorException(this.converts(from, to), text( 113 "Cannot convert ", from.identify, " to ", to, " expected original component of types: ", this.from, " and destination types of ", this.to 114 )); 115 116 if (to is typeid(string)) { 117 return from.unwrap!Element.text.pack(from, this, allocator); 118 } 119 120 if (to is typeid(CData[])) { 121 return from.unwrap!Element.cdatas.pack(from, this, allocator); 122 } 123 124 if (to is typeid(ProcessingInstruction[])) { 125 return from.unwrap!Element.pis.pack(from, this, allocator); 126 } 127 128 if (to is typeid(Element[])) { 129 return from.unwrap!Element.elements.pack(from, this, allocator); 130 } 131 132 if (to is typeid(Tag)) { 133 return from.unwrap!Element.tag.pack(from, this, allocator); 134 } 135 136 if (to is typeid(Text[])) { 137 return from.unwrap!Element.texts.pack(from, this, allocator); 138 } 139 140 if (to is typeid(Item[])) { 141 return from.unwrap!Element.items.pack(from, this, allocator); 142 } 143 144 throw new ConvertorException(text("Cannot convert ", from.identify, " expected component with one of types ", this.from)); 145 } 146 147 /** 148 Destroy component created using this convertor. 149 150 Destroy component created using this convertor. 151 Since convertor could potentially allocate memory for 152 converted component, only itself is containing history of allocation, 153 and therefore it is responsible as well to destroy and free allocated 154 memory with allocator. 155 156 Params: 157 converted = component that should be destroyed. 158 allocator = allocator used to allocate converted component. 159 **/ 160 void destruct(const TypeInfo from, ref Object converted, RCIAllocator allocator = theAllocator) const { 161 enforce!ConvertorException(this.convertsTo(converted), text("Cannot destroy component ", converted.identify, " that is not convertible by ", this)); 162 163 static foreach (ToType; DestinationTypes) { 164 if (converted.identify is typeid(ToType)) { 165 converted.unpack!ToType(allocator); 166 } 167 } 168 } 169 }