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 };