1 /** 2 * Deserialization into an existing D variable. 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.utils.sd.serialization.deserializer; 15 16 import std.algorithm.comparison; 17 import std.algorithm.iteration; 18 import std.traits : Unqual; 19 20 /// Sink for handling array items up to a given length 21 private struct MaxLengthArrayHandler( 22 /// Array element type 23 T, 24 /// Maximum number of elements to receive and store 25 size_t maxLength, 26 /// Object receiving the result, or handling overflow 27 ResultHandler, 28 ) 29 { 30 ResultHandler handler; 31 32 private: 33 T[maxLength] buf; 34 size_t pos; 35 36 public: // Handler interface 37 enum canHandleSlice(U) = is(Unqual!U == T); 38 void handleSlice(U)(U[] slice) 39 if (canHandleSlice!U) 40 { 41 auto end = pos + slice.length; 42 if (end > maxLength) 43 handler.handleOverflow(data, slice); 44 buf[pos .. end] = slice[]; 45 pos = end; 46 } 47 48 private struct ElementHandler 49 { 50 MaxLengthArrayHandler* arrayHandler; 51 52 enum bool canHandleValue(U) = is(Unqual!U == T); 53 void handleValue(U)(auto ref U value) 54 if (canHandleValue!U) 55 { 56 if (arrayHandler.pos == maxLength) 57 arrayHandler.handler.handleOverflow(arrayHandler.data, (&value)[0..1]); 58 arrayHandler.buf[arrayHandler.pos++] = value; 59 } 60 } 61 62 void handleElement(Reader)(Reader reader) 63 { 64 reader.read(ElementHandler(&this)); 65 } 66 67 void handleEnd() 68 { 69 handler.handleResult(data); 70 } 71 72 public: // Caller API 73 /// Get elements received so far 74 T[] data() { return buf[0 .. pos]; } 75 } 76 77 /// Sink for deserializing data into a variable of type `T`. 78 struct Deserializer(T) 79 { 80 T* target; 81 82 // Implements the top-level context handler 83 84 enum bool canHandleValue(U) = is(U : T); 85 void handleValue(U)(auto ref U value) 86 if (canHandleValue!U) 87 { 88 *target = value; 89 } 90 91 static if (is(T : real)) 92 { 93 void handleNumeric(Reader)(Reader reader) 94 { 95 struct ResultHandler 96 { 97 T* target; 98 99 void handleResult(char[] data) 100 { 101 import std.conv : to; 102 *target = data.to!T; 103 } 104 105 void handleOverflow(in char[] /*data*/, in char[] /*overflow*/) 106 { 107 throw new Exception("Numeric value is too long"); 108 } 109 } 110 111 // The longest number we can reasonably expect in the 112 // input which would still reasonably be parsed into a D 113 // numeric type. Integers already are bounded by a hard 114 // length limit, however, floating-point numbers can occur 115 // in inputs with arbitrary precision. Go with 64 total 116 // characters, which is more than double the amount of 117 // information that could be contained in the biggest D 118 // numeric type when expressed as a string. 119 enum maxLength = 64; 120 alias NumericArrayHandler = MaxLengthArrayHandler!( 121 char, 122 maxLength, 123 ResultHandler, 124 ); 125 126 auto handler = NumericArrayHandler(ResultHandler(target)); 127 reader.read(&handler); 128 } 129 } 130 131 static if (is(T == struct)) 132 { 133 static immutable string[] fieldNames = { 134 string[] result; 135 foreach (i, field; T.init.tupleof) 136 result ~= __traits(identifier, T.tupleof[i]); 137 return result; 138 }(); 139 140 enum maxLength = fieldNames.map!((string name) => name.length).fold!max(size_t(0)); 141 142 struct FieldNameHandler 143 { 144 struct ResultHandler 145 { 146 T* target; 147 148 void handleResult(char[] /*data*/) 149 { 150 } 151 152 void handleOverflow(in char[] data, in char[] overflow) 153 { 154 throw new Exception("No field with prefix " ~ cast(string)data ~ cast(string)overflow); 155 } 156 } 157 158 alias FieldNameArrayHandler = MaxLengthArrayHandler!(char, maxLength, ResultHandler); 159 FieldNameArrayHandler arrayHandler; 160 161 void handleArray(Reader)(Reader reader) 162 { 163 reader.read(&arrayHandler); 164 } 165 } 166 167 struct FieldHandler 168 { 169 T* target; 170 171 FieldNameHandler nameHandler; 172 173 void handlePairKey(Reader)(Reader reader) 174 { 175 reader.read(&nameHandler); 176 } 177 178 void handlePairValue(Reader)(Reader reader) 179 { 180 auto name = nameHandler.arrayHandler.data; 181 switch (name) 182 { 183 static foreach (i, fieldName; fieldNames) 184 case fieldName: 185 return reader.read(Deserializer!(typeof(T.tupleof[i]))(&target.tupleof[i])); 186 default: 187 throw new Exception("No field with prefix " ~ name.idup); 188 } 189 } 190 191 void handleEnd() {} 192 } 193 194 struct StructHandler 195 { 196 T* target; 197 198 void handlePair(Reader)(Reader reader) 199 { 200 reader.read(FieldHandler(target)); 201 } 202 203 void handleEnd() {} 204 } 205 206 void handleMap(Reader)(Reader reader) 207 { 208 reader.read(StructHandler(target)); 209 } 210 } 211 else 212 static if (is(T E : E[])) 213 { 214 struct ArrayHandler 215 { 216 T* target; 217 218 // TODO handleSlice 219 220 void handleElement(Reader)(Reader reader) 221 { 222 target.length++; 223 alias U = Unqual!E; 224 reader.read(.Deserializer!U(cast(U*)&(*target)[$ - 1])); 225 } 226 227 void handleEnd() {} 228 } 229 230 void handleArray(Reader)(Reader reader) 231 { 232 reader.read(ArrayHandler(target)); 233 } 234 } 235 } 236 237 /// Accept a data source and absorb received data into the given variable. 238 void deserializeInto(Source, T)(Source source, ref T target) 239 { 240 source.read(Deserializer!T(&target)); 241 } 242 243 /// Accept a data source and absorb received data into a new variable of type `T`. 244 T deserializeNew(T, Source)(Source source) 245 { 246 T target; 247 source.read(Deserializer!T(&target)); 248 return target; 249 }