1 module mir.toml.deserializer; 2 3 // debug = Deserializer; 4 5 static import toml; 6 7 import std.datetime.date; 8 import std.datetime.systime; 9 import std.meta; 10 11 import mir.timestamp : Timestamp; 12 13 template parseToml(T) 14 { 15 void parseToml(scope const(char)[] inputData, ref T serializer) @safe 16 { 17 auto document = toml.parseTOML(inputData); 18 serializeValue(document.table, serializer); 19 } 20 21 @safe pure: 22 23 private void serializeValue(scope toml.TOMLValue value, ref T serializer) 24 { 25 final switch (value.type) 26 { 27 case toml.TOML_TYPE.STRING: 28 serializeValue(value.str, serializer); 29 break; 30 case toml.TOML_TYPE.INTEGER: 31 serializeValue(value.integer, serializer); 32 break; 33 case toml.TOML_TYPE.FLOAT: 34 serializeValue(value.floating, serializer); 35 break; 36 case toml.TOML_TYPE.TRUE: 37 serializeValue(true, serializer); 38 break; 39 case toml.TOML_TYPE.FALSE: 40 serializeValue(false, serializer); 41 break; 42 case toml.TOML_TYPE.OFFSET_DATETIME: 43 serializeValue(value.offsetDatetime, serializer); 44 break; 45 case toml.TOML_TYPE.LOCAL_DATETIME: 46 serializeValue(value.localDatetime, serializer); 47 break; 48 case toml.TOML_TYPE.LOCAL_DATE: 49 serializeValue(value.localDate, serializer); 50 break; 51 case toml.TOML_TYPE.LOCAL_TIME: 52 serializeValue(value.localTime, serializer); 53 break; 54 case toml.TOML_TYPE.ARRAY: 55 serializeValue(value.array, serializer); 56 break; 57 case toml.TOML_TYPE.TABLE: 58 serializeValue(value.table, serializer); 59 break; 60 } 61 } 62 63 static foreach (SimpleType; AliasSeq!(bool, const(char)[], long, double)) 64 private void serializeValue(scope SimpleType value, ref T serializer) 65 { 66 serializer.putValue(value); 67 } 68 69 static foreach (TimeType; AliasSeq!(SysTime, DateTime, Date, TimeOfDay)) 70 private void serializeValue(scope TimeType value, ref T serializer) 71 { 72 serializer.putValue(Timestamp(value)); 73 } 74 75 private void serializeValue(scope toml.TOMLValue[] array, ref T serializer) 76 { 77 auto state = serializer.listBegin(array.length); 78 foreach (value; array) 79 { 80 serializer.elemBegin(); 81 serializeValue(value, serializer); 82 } 83 serializer.listEnd(state); 84 } 85 86 private void serializeValue(scope toml.TOMLValue[string] table, ref T serializer) 87 { 88 auto state = serializer.structBegin(table.length); 89 foreach (key, value; table) 90 { 91 serializer.putKey(key); 92 serializeValue(value, serializer); 93 } 94 serializer.structEnd(state); 95 } 96 } 97 98 debug (Deserializer) 99 { 100 import mir.ser; 101 import mir.bignum.decimal: Decimal; 102 import mir.bignum.integer: BigInt; 103 import mir.lob: Blob, Clob; 104 import mir.timestamp: Timestamp; 105 import mir.ion.type_code : IonTypeCode; 106 107 struct DebugSerializer(T) 108 { 109 import std.algorithm; 110 import std.range; 111 import std.stdio; 112 import std.string; 113 114 T forwarder; 115 private enum definedMethods = [ 116 "void putStringPart(scope const(char)[] value)", 117 "void stringEnd(size_t state)", 118 "size_t structBegin(size_t length = size_t.max)", 119 "void structEnd(size_t state)", 120 "size_t listBegin(size_t length = size_t.max)", 121 "void listEnd(size_t state)", 122 "size_t sexpBegin(size_t length = size_t.max)", 123 "void sexpEnd(size_t state)", 124 "void putSymbol(scope const char[] symbol)", 125 "void putAnnotation(scope const(char)[] annotation)", 126 "size_t annotationsEnd(size_t state)", 127 "size_t annotationWrapperBegin()", 128 "void annotationWrapperEnd(size_t annotationsState, size_t state)", 129 "void nextTopLevelValue()", 130 "void putKey(scope const char[] key)", 131 "void putValue(long value)", 132 "void putValue(ulong value)", 133 "void putValue(float value)", 134 "void putValue(double value)", 135 "void putValue(real value)", 136 "void putValue(scope ref const BigInt!128 value)", 137 "void putValue(scope ref const Decimal!128 value)", 138 "void putValue(typeof(null))", 139 "void putNull(IonTypeCode code)", 140 "void putValue(bool b)", 141 "void putValue(scope const char[] value)", 142 "void putValue(scope Clob value)", 143 "void putValue(scope Blob value)", 144 "void putValue(Timestamp value)", 145 "void elemBegin()", 146 "void sexpElemBegin()", 147 ]; 148 149 private static int prefixLength() 150 { 151 return __FUNCTION__.length - "prefixLength".length; 152 } 153 154 int fndepth; 155 156 @safe: 157 static foreach (method; definedMethods) 158 mixin(method ~ " pure { 159 enum fnname = __FUNCTION__[prefixLength..$]; 160 static if (fnname.length > 3 && fnname[$ - 3 .. $] == `End`) 161 fndepth--; 162 scope (exit) 163 { 164 static if (fnname.length > 5 && fnname[$ - 5 .. $] == `Begin` 165 && fnname != `elemBegin`) 166 fndepth++; 167 } 168 static if (is(typeof(return) == void)) 169 { 170 debug writeln(` `.repeat(fndepth).join, '\\x1B', `[1m`, fnname, '\\x1B', `[0m`, `(`, __traits(parameters), `)`); 171 __traits(getMember, forwarder, fnname)(__traits(parameters)); 172 } 173 else 174 { 175 debug write(` `.repeat(fndepth).join, '\\x1B', `[1m`, fnname, '\\x1B', `[0m`, `(`, __traits(parameters), `)`); 176 auto ret = __traits(getMember, forwarder, fnname)(__traits(parameters)); 177 debug writeln(` -> `, ret); 178 return ret; 179 } 180 }"); 181 } 182 183 private auto makeDebugSerializer(T)(lazy T forwarder) 184 { 185 return DebugSerializer!T(forwarder); 186 } 187 } 188 189 @trusted 190 immutable(ubyte)[] tomlToIon(scope const(char)[] inputData) 191 { 192 import std.algorithm : move; 193 import mir.appender : scopedBuffer; 194 import mir.ion.symbol_table: IonSymbolTable; 195 import mir.ion.internal.data_holder: ionPrefix; 196 import mir.ser.ion : ionSerializer; 197 import mir.serde : SerdeTarget; 198 enum nMax = 4096; 199 200 auto buf = scopedBuffer!ubyte; 201 202 IonSymbolTable!false table = void; 203 table.initialize; 204 205 debug (Deserializer) 206 { 207 auto debugSerializer = makeDebugSerializer(ionSerializer!(nMax * 8, null, false)); 208 debugSerializer.forwarder.initialize(table); 209 parseToml!(typeof(debugSerializer))(inputData, debugSerializer); 210 ref auto serializer() { return debugSerializer.forwarder; } 211 } 212 else 213 { 214 auto serializer = ionSerializer!(nMax * 8, null, false); 215 serializer.initialize(table); 216 parseToml!(typeof(serializer))(inputData, serializer); 217 } 218 219 serializer.finalize; 220 221 buf.put(ionPrefix); 222 if (table.initialized) 223 { 224 table.finalize; 225 buf.put(table.data); 226 } 227 buf.put(serializer.data); 228 229 return buf.data.idup; 230 } 231 232 template deserializeToml(T) 233 { 234 void deserializeToml(scope ref T value, scope const(char)[] data) 235 { 236 import mir.deser.ion : deserializeIon; 237 238 return deserializeIon!T(value, tomlToIon(data)); 239 } 240 241 T deserializeToml(scope const(char)[] data) 242 { 243 T value; 244 deserializeToml(value, data); 245 return value; 246 } 247 }