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.convertor.std_conv;
31 
32 import std.conv : to, ConvException, text;
33 import std.exception : enforce;
34 import std.typecons : Flag, Yes;
35 import std.traits : isSomeString;
36 import std.experimental.allocator;
37 import aermicioi.aedi_property_reader.convertor.convertor;
38 import aermicioi.aedi_property_reader.convertor.exception : ConvertorException;
39 import aermicioi.aedi_property_reader.convertor.placeholder;
40 import aermicioi.aedi_property_reader.convertor.mapper;
41 import aermicioi.aedi_property_reader.convertor.accessor;
42 import aermicioi.aedi_property_reader.convertor.setter;
43 import aermicioi.aedi_property_reader.convertor.inspector;
44 
45 /**
46 Convert from component to component using std.conv.to family of functions.
47 
48 Params:
49     from = original component to be converted
50     to = resulting component
51     allocator = ignored allocator as .to family of functions are not using allocators
52 Throws:
53     See std.conv.to for throwed exceptions
54 **/
55 void convert(To, From)(From from, ref To to, RCIAllocator allocator = theAllocator) {
56     to = from.to!To;
57 }
58 
59 /**
60 Destruct to component.
61 
62 Params:
63     to = component to destroy
64     allocator = ignored allocator as .to family of functions doesn't use allocators yet.
65 **/
66 void destruct(To)(ref To to, RCIAllocator allocator = theAllocator) {
67     destroy(to);
68     to = To.init;
69 }
70 
71 public {
72     alias AssociativeArrayAccessorFactory(T) = AssociativeArrayAccessor!(T[]);
73     alias AssociativeArrayInspectorFactory(T) = AssociativeArrayInspector!T;
74     alias AssociativeArraySetterFactory(T) = AssociativeArraySetter!T;
75 }
76 
77 class StdConvConvertor(To, From) : Convertor {
78 
79     mixin ConvertsFromToMixin!(From, To) DefaultImplementation;
80     mixin EqualToHashToStringOpCmpMixin;
81 
82     /**
83     ditto
84     **/
85     bool converts(in Object from, const TypeInfo to) @safe const nothrow {
86         if (DefaultImplementation.converts(from, to)) {
87             try {
88                 cast(void) from.unwrap!From.to!To;
89                 return true;
90             } catch (Exception e) {
91 
92                 return false;
93             }
94         }
95 
96         return false;
97     }
98 
99     /**
100     ditto
101     **/
102     bool converts(in Object from, in Object to) @safe const nothrow {
103         return this.converts(from, to.identify);
104     }
105 
106     /**
107     Convert from component to component.
108 
109     Params:
110         from = original component that is to be converted.
111         to = destination object that will be constructed out for original one.
112         allocator = optional allocator that could be used to construct to component.
113     Throws:
114         ConvertorException when there is a converting error
115         InvalidArgumentException when arguments passed are not of right type or state
116     Returns:
117         Resulting converted component.
118     **/
119     Object convert(in Object from, const TypeInfo to, RCIAllocator allocator = theAllocator) const {
120         enforce!ConvertorException(this.converts(from, to), text("Cannot convert ", from.identify, " to ", to, " expected origin of ", this.from, " and destination of ", this.to, ", or the input contains wrong information which does not match destination type."));
121 
122         return from.unwrap!From.to!To.pack(from, this, allocator);
123     }
124 
125     /**
126     Destroy component created using this convertor.
127 
128     Destroy component created using this convertor.
129     Since convertor could potentially allocate memory for
130     converted component, only itself is containing history of allocation,
131     and therefore it is responsible as well to destroy and free allocated
132     memory with allocator.
133 
134     Params:
135         converted = component that should be destroyed.
136         allocator = allocator used to allocate converted component.
137     **/
138     void destruct(const TypeInfo from, ref Object converted, RCIAllocator allocator = theAllocator) const {
139         enforce!ConvertorException(this.destroys(from, converted), text("Cannot destroy component of type ", to, " expected type of ", this.to));
140 
141         auto unpacked = converted.unpack!To;
142         destroy(unpacked);
143     }
144 }
145 
146 class StringStripperConvertor(StringType) : Convertor
147     if (isSomeString!StringType) {
148 
149     mixin ConvertsFromToMixin!(StringType, StringType) DefaultImplementation;
150     mixin EqualToHashToStringOpCmpMixin;
151 
152     /**
153     Convert from component to component.
154 
155     Params:
156         from = original component that is to be converted.
157         to = destination object that will be constructed out for original one.
158         allocator = optional allocator that could be used to construct to component.
159     Throws:
160         ConvertorException when there is a converting error
161         InvalidArgumentException when arguments passed are not of right type or state
162     Returns:
163         Resulting converted component.
164     **/
165     Object convert(in Object from, const TypeInfo to, RCIAllocator allocator = theAllocator) const {
166         import std..string : strip;
167         enforce!ConvertorException(this.converts(from, to), text("Cannot convert ", from.identify, " to ", to, " expected origin of ", this.from, " and destination of ", this.to));
168 
169         return from.unwrap!StringType.strip.pack(from, this, allocator);
170     }
171 
172     /**
173     Destroy component created using this convertor.
174 
175     Destroy component created using this convertor.
176     Since convertor could potentially allocate memory for
177     converted component, only itself is containing history of allocation,
178     and therefore it is responsible as well to destroy and free allocated
179     memory with allocator.
180 
181     Params:
182         converted = component that should be destroyed.
183         allocator = allocator used to allocate converted component.
184     **/
185     void destruct(const TypeInfo from, ref Object converted, RCIAllocator allocator = theAllocator) const {
186         enforce!ConvertorException(this.destroys(from, converted), text("Cannot destroy component of type ", to, " expected type of ", this.to));
187 
188         auto unpacked = converted.unpack!StringType;
189     }
190 }
191 
192 auto StdConvStringPrebuiltConvertorsFactory(CombinedConvertor defaultConvertor, Flag!"trimStringForNumbers" trimStringForNumbers = Yes.trimStringForNumbers) {
193     import std.meta;
194 
195     if (trimStringForNumbers) {
196         import std..string : strip;
197         import aermicioi.aedi_property_reader.convertor.chaining_convertor : ChainedConvertor;
198         static foreach (FromType; StringConvertibleTypes) {
199             static foreach (ToType; AliasSeq!(ScalarConvertibleTypes)) {
200                 defaultConvertor.add(
201                     new ChainedConvertor(
202                         new StringStripperConvertor!FromType,
203                         new StdConvConvertor!(ToType, FromType)
204                     )
205                 );
206             }
207         }
208     } else {
209         static foreach (FromType; StringConvertibleTypes) {
210             static foreach (ToType; ScalarConvertibleTypes) {
211                 defaultConvertor.add(new StdConvConvertor!(ToType, FromType));
212             }
213         }
214     }
215 
216     static foreach (FromType; StringConvertibleTypes) {
217         static foreach (ToType; StringConvertibleTypes) {
218             defaultConvertor.add(new StdConvConvertor!(ToType, FromType));
219         }
220     }
221 
222     static foreach (FromType; ScalarConvertibleTypes) {
223         static foreach (ToType; AliasSeq!(ScalarConvertibleTypes, StringConvertibleTypes)) {
224             defaultConvertor.add(new StdConvConvertor!(ToType, FromType));
225         }
226     }
227 
228     static foreach (FromType; AliasSeq!(StringConvertibleTypes, ScalarArrayConvertibleTypes)) {
229         static foreach (ToType; AliasSeq!(StringConvertibleTypes, ScalarArrayConvertibleTypes)) {
230             defaultConvertor.add(new StdConvConvertor!(ToType, FromType));
231         }
232     }
233 
234     static foreach (FromType; AliasSeq!(StringConvertibleTypes, StringArrayConvertibleTypes)) {
235         static foreach (ToType; AliasSeq!(StringConvertibleTypes, StringArrayConvertibleTypes)) {
236             defaultConvertor.add(new StdConvConvertor!(ToType, FromType));
237         }
238     }
239 
240     static foreach (FromType; AliasSeq!(StringConvertibleTypes, MapConvertibleTypes)) {
241         static foreach (ToType; AliasSeq!(StringConvertibleTypes, MapConvertibleTypes)) {
242             defaultConvertor.add(new StdConvConvertor!(ToType, FromType));
243         }
244     }
245 
246     defaultConvertor.add(new RangeToArrayConvertor!(dstring[], string[])(defaultConvertor));
247 };