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_property_reader.core.convertor;
33 import aermicioi.aedi_property_reader.core.accessor;
34 import aermicioi.aedi_property_reader.core.inspector;
35 import aermicioi.aedi_property_reader.xml.accessor;
36 import aermicioi.aedi_property_reader.xml.xml : accessor;
37 import aermicioi.aedi_property_reader.xml.inspector;
38 import aermicioi.aedi.exception;
39 import std.traits;
40 import std.xml;
41 import std.string : strip;
42 import std.conv : to, ConvException;
43 import std.experimental.allocator;
44 
45 public {
46     enum XmlAccessorFactory(From : XmlElement) = () => new RuntimeFieldAccessor!XmlElement(accessor());
47     enum XmlInspectorFactory(From : XmlElement) = () => new TaggedInspector!(XmlElement, Element)(new XmlInspector);
48 }
49 
50 alias XmlConvertor = ChainedAdvisedConvertor!(
51     AdvisedConvertor!(convert, destruct),
52     AdvisedConvertor!(
53         XmlAccessorFactory,
54         CompositeSetterFactory,
55         CompositeInspectorFactory,
56         XmlInspectorFactory
57     )
58 ).AdvisedConvertorImplementation;
59 
60 /**
61 Convert from Element into To scalar/array/assocarray value.
62 
63 As converting value only text of from element is taken into consideration.
64 
65 Params:
66     value = storage where to put converted from Element
67     from = the data that is to be converted.
68 Tohrows:
69     InvalidCastException when the type of value does not match stored data.
70 Returns:
71     value
72 **/
73 void convert(To, From : Element)(in From from, ref To value, RCIAllocator allocator = theAllocator)
74     if (isNumeric!To && !is(To == enum)) {
75 
76     try {
77 
78         value = from.text.strip.to!To;
79     } catch (ConvException e) {
80         throw new InvalidCastException(
81             "Could not convert xml " ~
82             from.toString() ~
83             " value to type " ~
84             fullyQualifiedName!To,
85             e
86         );
87     }
88 }
89 
90 void convert(To, From : Element)(in From from, ref To value, RCIAllocator allocator = theAllocator)
91     if (is(To : bool) && !is(To == enum)) {
92     import std.string : strip;
93 
94     try {
95 
96         value = from.text.strip.to!To;
97     } catch (ConvException e) {
98         throw new InvalidCastException(
99             "Could not convert xml " ~
100             from.toString() ~
101             " value to type " ~
102             fullyQualifiedName!To,
103             e
104         );
105     }
106 }
107 
108 /**
109 ditto
110 **/
111 void convert(To, From : Element)(in From from, ref To value, RCIAllocator allocator = theAllocator)
112     if ((isSomeString!To || isSomeChar!To) && !is(To == enum)) {
113 
114     try {
115 
116         value = from.text.to!To;
117     } catch (ConvException e) {
118         throw new InvalidCastException(
119             "Could not convert xml " ~
120             from.toString() ~
121             " value to type " ~
122             fullyQualifiedName!To,
123             e
124         );
125     }
126 }
127 
128 /**
129 ditto
130 **/
131 void convert(To : Z[], From : Element, Z)(in From from, ref To value, RCIAllocator allocator = theAllocator)
132     if (!isSomeString!To && !is(To == enum)) {
133 
134     value = allocator.makeArray!Z(from.elements.length);
135 
136     foreach (index, ref el; value) {
137         from.elements[index].convert(el, allocator);
138     }
139 }
140 
141 /**
142 ditto
143 **/
144 void convert(To : Z[string], From : Element, Z)(in From from, ref To value, RCIAllocator allocator = theAllocator) if (!is(To == enum)){
145 
146     foreach (ref el; from.elements) {
147 
148         Z temp;
149         el.convert(temp, allocator);
150         value[el.tag.name] = temp;
151     }
152 }
153 
154 /**
155 ditto
156 **/
157 void convert(To, From : Element)(in From from, ref To value, RCIAllocator allocator = theAllocator) if (is(To == enum)){
158 
159     string temp;
160     from.convert!string(temp, allocator);
161     value = temp.to!To;
162 	temp.destruct(allocator);
163 }
164 
165 void convert(To, From : string)(in From from, ref To value, RCIAllocator allocator = theAllocator) {
166 
167     value = from.to!To;
168 }
169 
170 void convert(To, From : XmlElement)(in From from, ref To value, RCIAllocator allocator = theAllocator) {
171 
172     final switch(from.kind) {
173         case XmlElement.Kind.element: {
174             (cast(const(Element)) from).convert(value, allocator);
175             break;
176         }
177         case XmlElement.Kind.attribute: {
178             (cast(const(string)) from).convert(value, allocator);
179             break;
180         }
181     }
182 }
183 
184 void destruct(To)(ref To to, RCIAllocator allocator = theAllocator) {
185     destroy(to);
186     to = To.init;
187 }
188 
189 void destruct(To : Z[], Z)(ref To to, RCIAllocator allocator = theAllocator)
190     if (!isSomeString!To) {
191     allocator.dispose(to);
192     to = To.init;
193 }