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 aermicioi 29 **/ 30 module aermicioi.aedi_property_reader.core.core; 31 32 import aermicioi.aedi.storage.storage; 33 import aermicioi.aedi.storage.locator; 34 import aermicioi.aedi_property_reader.core.convertor; 35 import aermicioi.aedi_property_reader.core.mapper; 36 import aermicioi.aedi_property_reader.core.document; 37 import std.meta; 38 import std.experimental.logger; 39 import std.exception; 40 41 /** 42 Configuration context that is providing a nice api to add convertors into a container for a document. 43 **/ 44 struct DocumentContainerBuilder(DocumentContainerType : Storage!(Convertor, string), alias AdvisedConvertor, F) { 45 46 alias FromType = F; 47 48 /** 49 Configured container. 50 **/ 51 DocumentContainerType container; 52 53 bool containerAsConvertor = true; 54 55 this(DocumentContainerType container, bool containerAsConvertor = true) { 56 this.container = container; 57 this.containerAsConvertor = containerAsConvertor; 58 59 static foreach (Type; AliasSeq!( 60 ubyte, byte, ushort, short, uint, int, ulong, long, float, double, real, char, wchar, dchar, 61 ubyte[], byte[], ushort[], short[], uint[], int[], ulong[], long[], float[], double[], real[], char[], wchar[], dchar[], string, wstring, dstring 62 )) { 63 this.register!(Type, Type); 64 } 65 } 66 67 /** 68 ditto 69 **/ 70 alias container this; 71 72 /** 73 Associate a convertor to a field in document that has property path, to be used for conversion. 74 75 Params: 76 To = the type of destination component that convertor should yield 77 path = property path for a field in document. 78 **/ 79 ref typeof(this) register(To)(string path) { 80 debug(trace) trace( 81 "Injecting convertor for ", 82 path, 83 " in document container to convert to ", 84 typeid(To), 85 " using ", 86 typeid(AdvisedConvertor!(To, FromType)()) 87 ); 88 89 auto convertor = AdvisedConvertor!(To, FromType)(); 90 91 return this.register(convertor, path); 92 } 93 94 /** 95 Associate a convertor to a type to be used by document when no specific convertor is provided for document field. 96 97 Params: 98 To = the type of destination component that convertor should yield 99 **/ 100 ref typeof(this) register(To)() { 101 102 return this.register!(To, To); 103 } 104 105 /** 106 Associate a convertor to a type for an interface to be used by document when no specific convertor is provided for document field. 107 108 Params: 109 Iface = interface for which the convertor is bound to. 110 To = the type of destination component that convertor should yield 111 **/ 112 ref typeof(this) register(Iface, To : Iface)() { 113 import std.traits : fullyQualifiedName; 114 115 return this.register!To(fullyQualifiedName!Iface); 116 } 117 118 ref typeof(this) register(Convertor convertor, string path) { 119 static if (is(DocumentContainerType : Convertor)) { 120 if (this.containerAsConvertor && (cast(CombinedConvertor) convertor !is null)) { 121 122 debug(trace) trace( 123 "Detected that document container ", typeid(DocumentContainerType), " provides converting capabilities, and injected convertor ", 124 convertor.classinfo, " accepts convertors, injecting container into convertor" 125 ); 126 (cast(CombinedConvertor) convertor).add(container); 127 } 128 } 129 130 this.container.set(convertor, path); 131 132 return this; 133 } 134 135 ref typeof(this) register(Convertor convertor) { 136 return this.register(convertor, convertor.to.toString); 137 } 138 139 alias property = register; 140 } 141 142 /** 143 Take a document container and create a configuration context for it. 144 145 Params: 146 container = container for which configuration context is created. 147 148 Returns: 149 DocumentContainerBuilder(DocumentContainerType, AdvisedConvertor, DocumentType, FromType) a configuration context 150 **/ 151 auto configure(DocumentContainerType : DocumentContainer!(DocumentType, FromType), alias AdvisedConvertor, DocumentType, FromType)(DocumentContainerType container) { 152 return DocumentContainerBuilder!(DocumentContainerType, AdvisedConvertor, FromType)(container); 153 } 154 155 /** 156 ditto 157 **/ 158 auto configure(DocumentContainerType : AdvisedDocumentContainer!(DocumentType, FromType, AdvisedConvertor), DocumentType, FromType, alias AdvisedConvertor)(DocumentContainerType container) { 159 return container.configure!(DocumentContainerType, AdvisedConvertor); 160 } 161 162 mixin template MapperBuilderMixin(AdvisedConvertors...) { 163 164 struct MapperBuilderImpl(MapperType : Mapper!(To, From), To, From) { 165 166 MapperType mapper; 167 168 alias mapper this; 169 170 ref auto register(To, From)() { 171 static foreach (AdvisedConvertor; AdvisedConvertors) { 172 static if (is(typeof(AdvisedConvertor.AdvisedConvertorImplementation!(To, From)))) { 173 enum converted = true; 174 mapper.convertors = mapper.convertors ~ AdvisedConvertor.AdvisedConvertorImplementation!(To, From)(); 175 } 176 } 177 178 static if (is(typeof(converted)) && !converted) { 179 static assert("Could not configure mapper with a convertor"); 180 } 181 182 return this; 183 } 184 185 struct WithFrom(With) { 186 187 ref auto register(To)() { 188 return register!(To, From); 189 } 190 } 191 192 struct WithTo(With) { 193 194 ref auto register(From)() { 195 return register!(To, From); 196 } 197 } 198 } 199 200 auto configure(MapperType : Mapper!(To, From), To, From)(MapperType mapper) { 201 return MapperBuilderImpl!MapperType(mapper); 202 } 203 } 204 205 import aermicioi.aedi_property_reader.core.std_conv; 206 import aermicioi.aedi_property_reader.core.convertor; 207 import aermicioi.aedi_property_reader.arg.convertor; 208 import aermicioi.aedi_property_reader.json.convertor; 209 import aermicioi.aedi_property_reader.xml.convertor; 210 import aermicioi.aedi_property_reader.yaml.convertor; 211 import aermicioi.aedi_property_reader.sdlang.convertor; 212 213 mixin MapperBuilderMixin!( 214 JsonConvertor, 215 XmlConvertor, 216 YamlConvertor, 217 SdlangConvertor, 218 ArgumentAdvisedConvertor, 219 StdConvAdvisedConvertor, 220 CompositeAdvisedConvertor 221 );