1 /** 2 * JSON decoding. 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.json.decoder; 15 16 import ae.utils.text : fromHex; 17 18 import std.exception : enforce; 19 import std.format; 20 import std.utf : encode; 21 22 struct JSONDecoder(C) 23 { 24 private: 25 C[] s; 26 size_t p; 27 28 C next() 29 { 30 enforce(p < s.length, "Unexpected end of JSON data"); 31 return s[p++]; 32 } 33 34 void skip() 35 { 36 p++; 37 } 38 39 C[] readN(size_t n) 40 { 41 auto end = p + n; 42 enforce(end <= s.length); 43 C[] result = s[p .. end]; 44 p = end; 45 return result; 46 } 47 48 C peek() 49 { 50 enforce(p < s.length); 51 return s[p]; 52 } 53 54 size_t mark() 55 { 56 return p; 57 } 58 59 C[] slice(size_t a, size_t b) 60 { 61 return s[a..b]; 62 } 63 64 @property bool eof() { return p == s.length; } 65 66 // ******************************************************************* 67 68 static bool isWhite(C c) 69 { 70 return c == ' ' || c == '\t'; 71 } 72 73 void skipWhitespace() 74 { 75 while (isWhite(peek())) 76 skip(); 77 } 78 79 void expect(C c) 80 { 81 auto n = next(); 82 enforce(n==c, "Expected %s, got %s".format(c, n)); 83 } 84 85 // ******************************************************************* 86 87 // The default reader 88 public @property ValueReader reader() { return ValueReader(&this); } 89 alias reader this; 90 91 struct ValueReader 92 { 93 JSONDecoder* json; 94 95 auto read(Handler)(Handler handler) 96 { 97 json.skipWhitespace(); 98 switch (json.peek()) 99 { 100 case '[': 101 static if (__traits(hasMember, Handler, q{handleArray})) 102 return handler.handleArray(ArrayReader(json)); 103 else 104 goto default; 105 case '"': 106 static if (__traits(hasMember, Handler, q{canHandleTypeHint}) && Handler.canHandleTypeHint!(C[])) 107 return handler.handleTypeHint!(C[])(this); 108 else 109 static if (__traits(hasMember, Handler, q{handleArray})) 110 return handler.handleArray(StringReader(json)); 111 else 112 goto default; 113 case 't': 114 static if (__traits(hasMember, Handler, q{canHandleValue}) && Handler.canHandleValue!bool) 115 { 116 json.skip(); 117 json.expect('r'); 118 json.expect('u'); 119 json.expect('e'); 120 return handler.handleValue!bool(true); 121 } 122 else 123 goto default; 124 case 'f': 125 static if (__traits(hasMember, Handler, q{canHandleValue}) && Handler.canHandleValue!bool) 126 { 127 json.skip(); 128 json.expect('a'); 129 json.expect('l'); 130 json.expect('s'); 131 json.expect('e'); 132 return handler.handleValue!bool(false); 133 } 134 else 135 goto default; 136 case 'n': 137 static if (__traits(hasMember, Handler, q{canHandleValue}) && Handler.canHandleValue!(typeof(null))) 138 { 139 json.skip(); 140 json.expect('u'); 141 json.expect('l'); 142 json.expect('l'); 143 return handler.handleValue!(typeof(null))(null); 144 } 145 else 146 goto default; 147 case '-': 148 case '0': 149 .. 150 case '9': 151 static if (__traits(hasMember, Handler, q{handleNumeric})) 152 return handler.handleNumeric(NumericReader(json)); 153 else 154 goto default; 155 case '{': 156 static if (__traits(hasMember, Handler, q{handleMap})) 157 return handler.handleMap(ObjectReader(json)); 158 else 159 goto default; 160 default: 161 throw new Exception("Unexpected JSON character: %s".format(json.peek())); 162 } 163 } 164 } 165 166 struct ArrayReader 167 { 168 JSONDecoder* json; 169 170 auto read(Handler)(Handler handler) 171 { 172 json.skip(); // '[' 173 if (json.peek() == ']') 174 { 175 json.skip(); 176 return handler.handleEnd(); 177 } 178 while (true) 179 { 180 handler.handleElement(ValueReader(json)); 181 json.skipWhitespace(); 182 if (json.peek()==']') 183 { 184 json.skip(); 185 return handler.handleEnd(); 186 } 187 else 188 json.expect(','); 189 } 190 } 191 192 } 193 194 struct ObjectReader 195 { 196 JSONDecoder* json; 197 198 void read(Handler)(Handler handler) 199 { 200 json.skip(); // '{' 201 json.skipWhitespace(); 202 if (json.peek()=='}') 203 { 204 json.skip(); 205 return handler.handleEnd(); 206 } 207 208 while (true) 209 { 210 handler.handlePair(ObjectPairReader(json)); 211 212 json.skipWhitespace(); 213 if (json.peek()=='}') 214 { 215 json.skip(); 216 return handler.handleEnd(); 217 } 218 else 219 json.expect(','); 220 } 221 } 222 } 223 224 struct ObjectPairReader 225 { 226 JSONDecoder* json; 227 228 auto read(Handler)(Handler handler) 229 { 230 handler.handlePairKey(ValueReader(json)); 231 json.skipWhitespace(); 232 json.expect(':'); 233 handler.handlePairValue(ValueReader(json)); 234 return handler.handleEnd(); 235 } 236 } 237 238 struct VarReader(V) 239 { 240 V v; 241 242 auto read(Handler)(Handler handler) 243 { 244 static assert(__traits(hasMember, Handler, q{canHandleValue}), 245 Handler.stringof ~ " can't accept values"); 246 static assert(Handler.canHandleValue!V, 247 Handler.stringof ~ " can't accept values of type " ~ V.stringof); 248 return handler.handleValue!V(v); 249 } 250 } 251 252 struct StringReader 253 { 254 JSONDecoder* json; 255 256 void read(Handler)(Handler handler) 257 { 258 json.skip(); // '"' 259 260 auto start = json.mark(); 261 262 void sendSlice(K)(K[] slice) 263 { 264 static if (__traits(hasMember, Handler, q{canHandleSlice}) && Handler.canHandleSlice!(K[])) 265 handler.handleSlice(slice); 266 else 267 foreach (c; slice) 268 handler.handleElement(VarReader!K(c)); 269 } 270 271 void flush() 272 { 273 auto end = json.mark(); 274 if (start != end) 275 sendSlice(json.slice(start, end)); 276 } 277 278 void oneConst(C c)() 279 { 280 static C[1] arr = [c]; 281 sendSlice(arr[]); 282 } 283 284 while (true) 285 { 286 C c = json.peek(); 287 if (c=='"') 288 { 289 flush(); 290 json.skip(); 291 return; 292 } 293 else 294 if (c=='\\') 295 { 296 flush(); 297 json.skip(); 298 switch (json.next()) 299 { 300 case '"': oneConst!('"'); break; 301 case '/': oneConst!('/'); break; 302 case '\\': oneConst!('\\'); break; 303 case 'b': oneConst!('\b'); break; 304 case 'f': oneConst!('\f'); break; 305 case 'n': oneConst!('\n'); break; 306 case 'r': oneConst!('\r'); break; 307 case 't': oneConst!('\t'); break; 308 case 'u': 309 { 310 auto w = cast(wchar)fromHex!ushort(json.readN(4)); 311 static if (C.sizeof == 1) 312 { 313 char[4] buf; 314 sendSlice(buf[0 .. encode(buf, w)]); 315 } 316 else 317 { 318 Unqual!C[1] buf; 319 buf[0] = w; 320 sendSlice(buf[]); 321 } 322 break; 323 } 324 default: enforce(false, "Unknown escape"); 325 } 326 start = json.mark(); 327 } 328 else 329 json.skip(); 330 } 331 } 332 } 333 334 struct NumericReader 335 { 336 JSONDecoder* json; 337 338 auto read(Handler)(Handler handler) 339 { 340 auto p = json.mark(); 341 342 static immutable bool[256] numeric = 343 [ 344 '0':true, 345 '1':true, 346 '2':true, 347 '3':true, 348 '4':true, 349 '5':true, 350 '6':true, 351 '7':true, 352 '8':true, 353 '9':true, 354 '.':true, 355 '-':true, 356 '+':true, 357 'e':true, 358 'E':true, 359 ]; 360 361 while (!json.eof() && numeric[json.peek()]) // TODO wchar/dchar OOB 362 json.skip(); 363 handler.handleSlice!C(json.slice(p, json.mark())); 364 return handler.handleEnd(); 365 } 366 } 367 } 368 369 auto decodeJSON(C)(C[] s) 370 { 371 return JSONDecoder!C(s); 372 } 373 374 unittest 375 { 376 import ae.utils.sd.serialization.deserializer : deserializeInto; 377 378 { 379 struct S { string str; int i; } 380 S s; 381 `{"str":"Hello","i":42}` 382 .decodeJSON() 383 .deserializeInto(s); 384 assert(s.str == "Hello"); 385 assert(s.i == 42); 386 } 387 388 { 389 string s; 390 `"Hello\nworld"` 391 .decodeJSON() 392 .deserializeInto(s); 393 assert(s == "Hello\nworld"); 394 } 395 }