1 /** 2 JSON serialization and value handling. 3 4 This module provides the Json struct for reading, writing and manipulating 5 JSON values. De(serialization) of arbitrary D types is also supported and 6 is recommended for handling JSON in performance sensitive applications. 7 8 Copyright: © 2012-2015 Sönke Ludwig 9 License: Subject to the terms of the MIT license, as written in the included LICENSE.txt file. 10 Authors: Sönke Ludwig 11 */ 12 module vibe.data.json; 13 14 /// 15 @safe unittest { 16 void manipulateJson(Json j) 17 { 18 import std.stdio; 19 20 // retrieving the values is done using get() 21 assert(j["name"].get!string == "Example"); 22 assert(j["id"].get!int == 1); 23 24 // semantic conversions can be done using to() 25 assert(j["id"].to!string == "1"); 26 27 // prints: 28 // name: "Example" 29 // id: 1 30 foreach (key, value; j.byKeyValue) 31 writefln("%s: %s", key, value); 32 33 // print out as JSON: {"name": "Example", "id": 1} 34 writefln("JSON: %s", j.toString()); 35 36 // DEPRECATED: object members can be accessed using member syntax, just like in JavaScript 37 //j = Json.emptyObject; 38 //j.name = "Example"; 39 //j.id = 1; 40 } 41 } 42 43 /// Constructing `Json` objects 44 @safe unittest { 45 // construct a JSON object {"field1": "foo", "field2": 42, "field3": true} 46 47 // using the constructor 48 Json j1 = Json(["field1": Json("foo"), "field2": Json(42), "field3": Json(true)]); 49 50 // using piecewise construction 51 Json j2 = Json.emptyObject; 52 j2["field1"] = "foo"; 53 j2["field2"] = 42.0; 54 j2["field3"] = true; 55 56 // using serialization 57 struct S { 58 string field1; 59 double field2; 60 bool field3; 61 } 62 Json j3 = S("foo", 42, true).serializeToJson(); 63 64 // using serialization, converting directly to a JSON string 65 string j4 = S("foo", 32, true).serializeToJsonString(); 66 } 67 68 69 public import vibe.data.serialization; 70 public import std.json : JSONException; 71 72 import vibe.internal.conv : enumToString, formattedWriteFixed; 73 74 import std.algorithm; 75 import std.array; 76 import std.bigint; 77 import std.conv; 78 import std.datetime; 79 import std.exception; 80 import std.format : FormatSpec, format; 81 import std.json : JSONValue, JSONType; 82 import std.range; 83 import std.string; 84 import std.traits; 85 import std.typecons : Tuple; 86 import std.uuid; 87 88 /******************************************************************************/ 89 /* public types */ 90 /******************************************************************************/ 91 92 /** 93 Represents a single JSON value. 94 95 Json values can have one of the types defined in the Json.Type enum. They 96 behave mostly like values in ECMA script in the way that you can 97 transparently perform operations on them. However, strict typechecking is 98 done, so that operations between differently typed JSON values will throw 99 a JSONException. Additionally, an explicit cast or using get!() or to!() is 100 required to convert a JSON value to the corresponding static D type. 101 */ 102 struct Json { 103 @safe: 104 105 static assert(!hasElaborateDestructor!BigInt && !hasElaborateCopyConstructor!BigInt, 106 "struct Json is missing required ~this and/or this(this) members for BigInt."); 107 108 private { 109 union { 110 BigInt m_bigInt; 111 long m_int; 112 double m_float; 113 bool m_bool; 114 string m_string; 115 Json[string] m_object; 116 Json[] m_array; 117 FillerType m_filler; 118 } 119 120 Type m_type = Type.undefined; 121 122 version (VibeJsonFieldNames) { 123 string m_name; 124 } 125 } 126 127 // we should just use ubyte[exactSize] in the union, 128 // but using a static array there breaks ctfe. 129 // so just replace it with a struct with enough fields to cover every other type. 130 // Note that this will round Json's size to the nearest word-size, 131 // but that's okay because we want to be word aligned anyways. 132 private struct FillerType 133 { 134 static import std.meta; 135 136 enum exactSize = Largest!(BigInt, long, double, bool, string, Json[string], Json[]).sizeof; 137 enum numFields = (exactSize + size_t.sizeof - 1) / size_t.sizeof; 138 139 std.meta.Repeat!(numFields, size_t) fields; 140 } 141 142 /** Represents the run time type of a JSON value. 143 */ 144 enum Type { 145 undefined, /// A non-existent value in a JSON object 146 null_, /// Null value 147 bool_, /// Boolean value 148 int_, /// 64-bit integer value 149 bigInt, /// BigInt values 150 float_, /// 64-bit floating point value 151 string, /// UTF-8 string 152 array, /// Array of JSON values 153 object, /// JSON object aka. dictionary from string to Json 154 155 deprecated("Use `undefined` instead.") Undefined = undefined, /// Compatibility alias 156 deprecated("Use `null_` instead.") Null = null_, /// Compatibility alias 157 deprecated("Use `bool_` instead.") Bool = bool_, /// Compatibility alias 158 deprecated("Use `int_` instead.") Int = int_, /// Compatibility alias 159 deprecated("Use `float_` instead.") Float = float_, /// Compatibility alias 160 deprecated("Use `string` instead.") String = string, /// Compatibility alias 161 deprecated("Use `array` instead.") Array = array, /// Compatibility alias 162 deprecated("Use `object` instead.") Object = object /// Compatibility alias 163 } 164 165 /// New JSON value of Type.Undefined 166 static @property Json undefined() nothrow { return Json(); } 167 168 /// New JSON value of Type.Object 169 static @property Json emptyObject() nothrow { return Json(cast(Json[string])null); } 170 171 /// New JSON value of Type.Array 172 static @property Json emptyArray() nothrow { return Json(cast(Json[])null); } 173 174 version(JsonLineNumbers) int line; 175 176 /** 177 Constructor for a JSON object. 178 */ 179 this(typeof(null)) nothrow { zeroFields; m_type = Type.null_; } 180 /// ditto 181 this(bool v) nothrow { zeroFields; m_type = Type.bool_; m_bool = v; } 182 /// ditto 183 this(byte v) nothrow { this(cast(long)v); } 184 /// ditto 185 this(ubyte v) nothrow { this(cast(long)v); } 186 /// ditto 187 this(short v) nothrow { this(cast(long)v); } 188 /// ditto 189 this(ushort v) nothrow { this(cast(long)v); } 190 /// ditto 191 this(int v) nothrow { this(cast(long)v); } 192 /// ditto 193 this(uint v) nothrow { this(cast(long)v); } 194 /// ditto 195 this(long v) nothrow { zeroFields; m_type = Type.int_; m_int = v; } 196 /// ditto 197 this(BigInt v) nothrow @trusted { zeroFields; m_type = Type.bigInt; initBigInt(); m_bigInt = v; } 198 /// ditto 199 this(double v) nothrow { zeroFields; m_type = Type.float_; m_float = v; } 200 /// ditto 201 this(string v) nothrow @trusted { zeroFields; m_type = Type..string; m_string = v; } 202 /// ditto 203 this(Json[] v) nothrow @trusted { zeroFields; m_type = Type.array; m_array = v; } 204 /// ditto 205 this(Json[string] v) nothrow @trusted { zeroFields; m_type = Type.object; m_object = v; } 206 207 // used internally for UUID serialization support 208 private this(UUID v) nothrow { this(v.toString()); } 209 210 // ensure that stale pointers in unused union memory don't cause leaks 211 private void zeroFields() nothrow { m_filler = FillerType.init; } 212 213 /** 214 Converts a std.json.JSONValue object to a vibe Json object. 215 */ 216 this(in JSONValue value) { 217 final switch (value.type) { 218 case JSONType.null_: this = null; break; 219 case JSONType.object: 220 this = emptyObject; 221 () @trusted { 222 foreach (string k, ref const JSONValue v; value.object) 223 this[k] = Json(v); 224 } (); 225 break; 226 case JSONType.array: 227 this = (() @trusted => Json(value.array.map!(a => Json(a)).array))(); 228 break; 229 case JSONType..string: this = value.str; break; 230 case JSONType.integer: this = value.integer; break; 231 case JSONType.uinteger: this = BigInt(value.uinteger); break; 232 case JSONType.float_: this = value.floating; break; 233 case JSONType.true_: this = true; break; 234 case JSONType.false_: this = false; break; 235 } 236 } 237 238 239 /** 240 Allows assignment of D values to a JSON value. 241 */ 242 ref Json opAssign(Json v) return @trusted 243 nothrow { 244 if (v.type != Type.bigInt) 245 runDestructors(); 246 auto old_type = m_type; 247 m_type = v.m_type; 248 final switch(m_type){ 249 case Type.undefined: m_string = null; break; 250 case Type.null_: m_string = null; break; 251 case Type.bool_: m_bool = v.m_bool; break; 252 case Type.int_: m_int = v.m_int; break; 253 case Type.bigInt: 254 if (old_type != Type.bigInt) 255 initBigInt(); 256 m_bigInt = v.m_bigInt; 257 break; 258 case Type.float_: m_float = v.m_float; break; 259 case Type..string: m_string = v.m_string; break; 260 case Type.array: opAssign(v.m_array); break; 261 case Type.object: opAssign(v.m_object); break; 262 } 263 return this; 264 } 265 /// ditto 266 void opAssign(typeof(null)) nothrow @trusted { runDestructors(); m_type = Type.null_; m_string = null; } 267 /// ditto 268 bool opAssign(bool v) nothrow { runDestructors(); m_type = Type.bool_; m_bool = v; return v; } 269 /// ditto 270 int opAssign(int v) nothrow { runDestructors(); m_type = Type.int_; m_int = v; return v; } 271 /// ditto 272 long opAssign(long v) nothrow { runDestructors(); m_type = Type.int_; m_int = v; return v; } 273 /// ditto 274 BigInt opAssign(BigInt v) 275 nothrow @trusted { 276 if (m_type != Type.bigInt) 277 initBigInt(); 278 m_type = Type.bigInt; 279 m_bigInt = v; 280 return v; 281 } 282 /// ditto 283 double opAssign(double v) nothrow { runDestructors(); m_type = Type.float_; m_float = v; return v; } 284 /// ditto 285 string opAssign(string v) nothrow @trusted { runDestructors(); m_type = Type..string; m_string = v; return v; } 286 /// ditto 287 Json[] opAssign(Json[] v) 288 nothrow @trusted { 289 runDestructors(); 290 m_type = Type.array; 291 m_array = v; 292 version (VibeJsonFieldNames) { 293 try { 294 foreach (idx, ref av; m_array) 295 av.m_name = format("%s[%s]", m_name, idx); 296 } catch (Exception e) assert(false, e.msg); 297 } 298 return v; 299 } 300 /// ditto 301 Json[string] opAssign(Json[string] v) 302 nothrow @trusted { 303 runDestructors(); 304 m_type = Type.object; 305 m_object = v; 306 version (VibeJsonFieldNames) { 307 try { 308 foreach (key, ref av; m_object) 309 av.m_name = format("%s.%s", m_name, key); 310 } catch (Exception e) assert(false, e.msg); 311 } 312 return v; 313 } 314 315 // used internally for UUID serialization support 316 private UUID opAssign(UUID v) nothrow { opAssign(v.toString()); return v; } 317 318 /** 319 Allows removal of values from Type.Object Json objects. 320 */ 321 void remove(string item) @trusted { checkType!(Json[string])(); m_object.remove(item); } 322 323 /** 324 The current type id of this JSON object. 325 */ 326 @property Type type() const nothrow { return m_type; } 327 328 /** 329 Clones a JSON value recursively. 330 */ 331 Json clone() 332 const nothrow @trusted { 333 final switch (m_type) { 334 case Type.undefined: return Json.undefined; 335 case Type.null_: return Json(null); 336 case Type.bool_: return Json(m_bool); 337 case Type.int_: return Json(m_int); 338 case Type.bigInt: return Json(m_bigInt); 339 case Type.float_: return Json(m_float); 340 case Type..string: return Json(m_string); 341 case Type.array: 342 Json[] ret; 343 foreach (v; m_array) ret ~= v.clone(); 344 return Json(ret); 345 case Type.object: 346 Json[string] ret; 347 foreach (kv; m_object.byKeyValue) 348 ret[kv.key] = kv.value.clone(); 349 return Json(ret); 350 } 351 } 352 353 /** 354 Allows direct indexing of array typed JSON values. 355 */ 356 ref inout(Json) opIndex(size_t idx) inout @trusted { checkType!(Json[])(); return m_array[idx]; } 357 358 /// 359 @safe unittest { 360 Json value = Json.emptyArray; 361 value ~= 1; 362 value ~= true; 363 value ~= "foo"; 364 assert(value[0] == 1); 365 assert(value[1] == true); 366 assert(value[2] == "foo"); 367 } 368 369 370 /** 371 Allows direct indexing of object typed JSON values using a string as 372 the key. 373 374 Returns an object of `Type.undefined` if the key was not found. 375 */ 376 const(Json) opIndex(string key) 377 const @trusted { 378 checkType!(Json[string])(); 379 if( auto pv = key in m_object ) return *pv; 380 Json ret = Json.undefined; 381 ret.m_string = key; 382 version (VibeJsonFieldNames) ret.m_name = format("%s.%s", m_name, key); 383 return ret; 384 } 385 /// ditto 386 ref Json opIndex(string key) 387 @trusted { 388 checkType!(Json[string])(); 389 if( auto pv = key in m_object ) 390 return *pv; 391 if (m_object is null) { 392 m_object = ["": Json.init]; 393 m_object.remove(""); 394 } 395 m_object[key] = Json.init; 396 auto nv = key in m_object; 397 assert(m_object !is null); 398 assert(nv !is null, "Failed to insert key '"~key~"' into AA!?"); 399 nv.m_type = Type.undefined; 400 assert(nv.type == Type.undefined); 401 nv.m_string = key; 402 version (VibeJsonFieldNames) nv.m_name = format("%s.%s", m_name, key); 403 return *nv; 404 } 405 406 /// 407 @safe unittest { 408 Json value = Json.emptyObject; 409 value["a"] = 1; 410 value["b"] = true; 411 value["c"] = "foo"; 412 assert(value["a"] == 1); 413 assert(value["b"] == true); 414 assert(value["c"] == "foo"); 415 assert(value["not-existing"].type() == Type.undefined); 416 } 417 418 /** 419 Returns a slice of a JSON array. 420 */ 421 inout(Json[]) opSlice() 422 inout @trusted { 423 checkType!(Json[])(); 424 return m_array; 425 } 426 /// 427 inout(Json[]) opSlice(size_t from, size_t to) 428 inout @trusted { 429 checkType!(Json[])(); 430 return m_array[from .. to]; 431 } 432 433 /** 434 Returns the number of entries of string, array or object typed JSON values. 435 */ 436 @property size_t length() 437 const @trusted { 438 checkType!(string, Json[], Json[string])("property length"); 439 switch(m_type){ 440 case Type..string: return m_string.length; 441 case Type.array: return m_array.length; 442 case Type.object: return m_object.length; 443 default: assert(false); 444 } 445 } 446 447 /** 448 Allows foreach iterating over JSON objects and arrays. 449 */ 450 int opApply(scope int delegate(ref Json obj) del) 451 @system { 452 checkType!(Json[], Json[string])("opApply"); 453 if( m_type == Type.array ){ 454 foreach( ref v; m_array ) 455 if( auto ret = del(v) ) 456 return ret; 457 return 0; 458 } else { 459 foreach( ref v; m_object ) 460 if( v.type != Type.undefined ) 461 if( auto ret = del(v) ) 462 return ret; 463 return 0; 464 } 465 } 466 /// ditto 467 int opApply(scope int delegate(ref const Json obj) del) 468 const @system { 469 checkType!(Json[], Json[string])("opApply"); 470 if( m_type == Type.array ){ 471 foreach( ref v; m_array ) 472 if( auto ret = del(v) ) 473 return ret; 474 return 0; 475 } else { 476 foreach( ref v; m_object ) 477 if( v.type != Type.undefined ) 478 if( auto ret = del(v) ) 479 return ret; 480 return 0; 481 } 482 } 483 /// ditto 484 int opApply(scope int delegate(ref size_t idx, ref Json obj) del) 485 @system { 486 checkType!(Json[])("opApply"); 487 foreach( idx, ref v; m_array ) 488 if( auto ret = del(idx, v) ) 489 return ret; 490 return 0; 491 } 492 /// ditto 493 int opApply(scope int delegate(ref size_t idx, ref const Json obj) del) 494 const @system { 495 checkType!(Json[])("opApply"); 496 foreach( idx, ref v; m_array ) 497 if( auto ret = del(idx, v) ) 498 return ret; 499 return 0; 500 } 501 /// ditto 502 int opApply(scope int delegate(ref string idx, ref Json obj) del) 503 @system { 504 checkType!(Json[string])("opApply"); 505 foreach( idx, ref v; m_object ) 506 if( v.type != Type.undefined ) 507 if( auto ret = del(idx, v) ) 508 return ret; 509 return 0; 510 } 511 /// ditto 512 int opApply(scope int delegate(ref string idx, ref const Json obj) del) 513 const @system { 514 checkType!(Json[string])("opApply"); 515 foreach( idx, ref v; m_object ) 516 if( v.type != Type.undefined ) 517 if( auto ret = del(idx, v) ) 518 return ret; 519 return 0; 520 } 521 522 private alias KeyValue = Tuple!(string, "key", Json, "value"); 523 524 /// Iterates over all key/value pairs of an object. 525 @property auto byKeyValue() 526 @trusted { 527 checkType!(Json[string])("byKeyValue"); 528 return m_object.byKeyValue.map!(kv => KeyValue(kv.key, kv.value)).trustedRange; 529 } 530 /// ditto 531 @property auto byKeyValue() 532 const @trusted { 533 checkType!(Json[string])("byKeyValue"); 534 return m_object.byKeyValue.map!(kv => const(KeyValue)(kv.key, kv.value)).trustedRange; 535 } 536 /// Iterates over all index/value pairs of an array. 537 @property auto byIndexValue() 538 @trusted { 539 checkType!(Json[])("byIndexValue"); 540 return zip(iota(0, m_array.length), m_array); 541 } 542 /// ditto 543 @property auto byIndexValue() 544 const @trusted { 545 checkType!(Json[])("byIndexValue"); 546 return zip(iota(0, m_array.length), m_array); 547 } 548 /// Iterates over all values of an object or array. 549 @property auto byValue() 550 @trusted { 551 checkType!(Json[], Json[string])("byValue"); 552 static struct Rng { 553 private { 554 bool isArray; 555 Json[] array; 556 typeof(Json.init.m_object.byValue) object; 557 } 558 559 bool empty() @trusted nothrow { if (isArray) return array.length == 0; else return object.empty; } 560 auto front() @trusted nothrow { if (isArray) return array[0]; else return object.front; } 561 void popFront() @trusted nothrow { if (isArray) array = array[1 .. $]; else object.popFront(); } 562 } 563 564 if (m_type == Type.array) return Rng(true, m_array); 565 else return Rng(false, null, m_object.byValue); 566 } 567 /// ditto 568 @property auto byValue() 569 const @trusted { 570 checkType!(Json[], Json[string])("byValue"); 571 static struct Rng { 572 @safe: 573 private { 574 bool isArray; 575 const(Json)[] array; 576 typeof(const(Json).init.m_object.byValue) object; 577 } 578 579 bool empty() @trusted nothrow { if (isArray) return array.length == 0; else return object.empty; } 580 auto front() @trusted nothrow { if (isArray) return array[0]; else return object.front; } 581 void popFront() @trusted nothrow { if (isArray) array = array[1 .. $]; else object.popFront(); } 582 } 583 584 if (m_type == Type.array) return Rng(true, m_array); 585 else return Rng(false, null, m_object.byValue); 586 } 587 588 589 /** 590 Converts this Json object to a std.json.JSONValue object 591 */ 592 T opCast(T)() const 593 if (is(T == JSONValue)) 594 { 595 final switch (type) { 596 case Json.Type.undefined: 597 case Json.Type.null_: 598 return JSONValue(null); 599 case Json.Type.bool_: 600 return JSONValue(get!bool); 601 case Json.Type.int_: 602 return JSONValue(get!long); 603 case Json.Type.bigInt: 604 auto bi = get!BigInt; 605 if (bi > long.max) 606 return JSONValue((() @trusted => cast(ulong)get!BigInt)()); 607 else 608 return JSONValue((() @trusted => cast(long)get!BigInt)()); 609 case Json.Type.float_: 610 return JSONValue(get!double); 611 case Json.Type..string: 612 return JSONValue(get!string); 613 case Json.Type.array: 614 JSONValue[] ret; 615 foreach (ref const Json e; byValue) 616 ret ~= cast(JSONValue)e; 617 return JSONValue(ret); 618 case Json.Type.object: 619 JSONValue[string] ret; 620 foreach (string k, ref const Json e; byKeyValue) { 621 if( e.type == Json.Type.undefined ) continue; 622 ret[k] = cast(JSONValue)e; 623 } 624 return JSONValue(ret); 625 } 626 } 627 628 629 /** 630 Converts the JSON value to the corresponding D type - types must match exactly. 631 632 Available_Types: 633 $(UL 634 $(LI `bool` (`Type.bool_`)) 635 $(LI `double` (`Type.float_`)) 636 $(LI `float` (Converted from `double`)) 637 $(LI `long` (`Type.int_`)) 638 $(LI `ulong`, `int`, `uint`, `short`, `ushort`, `byte`, `ubyte` (Converted from `long`)) 639 $(LI `string` (`Type.string`)) 640 $(LI `Json[]` (`Type.array`)) 641 $(LI `Json[string]` (`Type.object`)) 642 ) 643 644 See_Also: `opt`, `to`, `deserializeJson` 645 */ 646 inout(T) opCast(T)() inout if (!is(T == JSONValue)) { return get!T; } 647 /// ditto 648 @property inout(T) get(T)() 649 inout @trusted { 650 static if (!is(T : bool) && is(T : long)) 651 checkType!(long, BigInt)(); 652 else 653 checkType!T(); 654 655 static if (is(T == bool)) return m_bool; 656 else static if (is(T == double)) return m_float; 657 else static if (is(T == float)) return cast(T)m_float; 658 else static if (is(T == string)) return m_string; 659 else static if (is(T == UUID)) return UUID(m_string); 660 else static if (is(T == Json[])) return m_array; 661 else static if (is(T == Json[string])) return m_object; 662 else static if (is(T == BigInt)) return m_type == Type.bigInt ? m_bigInt : BigInt(m_int); 663 else static if (is(T : long)) { 664 if (m_type == Type.bigInt) { 665 enforceJson(m_bigInt <= T.max && m_bigInt >= T.min, "Integer conversion out of bounds error"); 666 return cast(T)m_bigInt.toLong(); 667 } else { 668 enforceJson(m_int <= T.max && m_int >= T.min, "Integer conversion out of bounds error"); 669 return cast(T)m_int; 670 } 671 } 672 else static assert(0, "JSON can only be cast to (bool, long, std.bigint.BigInt, double, string, Json[] or Json[string]. Not "~T.stringof~"."); 673 } 674 675 /** 676 Returns the native type for this JSON if it matches the current runtime type. 677 678 If the runtime type does not match the given native type, the 'def' parameter is returned 679 instead. 680 681 See_Also: `get` 682 */ 683 @property const(T) opt(T)(const(T) def = T.init) 684 const { 685 if( typeId!T != m_type ) return def; 686 return get!T; 687 } 688 /// ditto 689 @property T opt(T)(T def = T.init) 690 { 691 if( typeId!T != m_type ) return def; 692 return get!T; 693 } 694 695 /** 696 Converts the JSON value to the corresponding D type - types are converted as necessary. 697 698 Automatically performs conversions between strings and numbers. See 699 `get` for the list of available types. For converting/deserializing 700 JSON to complex data types see `deserializeJson`. 701 702 See_Also: `get`, `deserializeJson` 703 */ 704 @property inout(T) to(T)() 705 inout @trusted { 706 static if( is(T == bool) ){ 707 final switch( m_type ){ 708 case Type.undefined: return false; 709 case Type.null_: return false; 710 case Type.bool_: return m_bool; 711 case Type.int_: return m_int != 0; 712 case Type.bigInt: return m_bigInt != 0; 713 case Type.float_: return m_float != 0; 714 case Type..string: return m_string.length > 0; 715 case Type.array: return m_array.length > 0; 716 case Type.object: return m_object.length > 0; 717 } 718 } else static if( is(T == double) ){ 719 final switch( m_type ){ 720 case Type.undefined: return T.init; 721 case Type.null_: return 0; 722 case Type.bool_: return m_bool ? 1 : 0; 723 case Type.int_: return m_int; 724 case Type.bigInt: return bigIntToLong(); 725 case Type.float_: return m_float; 726 case Type..string: return .to!double(cast(string)m_string); 727 case Type.array: return double.init; 728 case Type.object: return double.init; 729 } 730 } else static if( is(T == float) ){ 731 final switch( m_type ){ 732 case Type.undefined: return T.init; 733 case Type.null_: return 0; 734 case Type.bool_: return m_bool ? 1 : 0; 735 case Type.int_: return m_int; 736 case Type.bigInt: return bigIntToLong(); 737 case Type.float_: return m_float; 738 case Type..string: return .to!float(cast(string)m_string); 739 case Type.array: return float.init; 740 case Type.object: return float.init; 741 } 742 } else static if( is(T == long) ){ 743 final switch( m_type ){ 744 case Type.undefined: return 0; 745 case Type.null_: return 0; 746 case Type.bool_: return m_bool ? 1 : 0; 747 case Type.int_: return m_int; 748 case Type.bigInt: return cast(long)bigIntToLong(); 749 case Type.float_: return cast(long)m_float; 750 case Type..string: return .to!long(m_string); 751 case Type.array: return 0; 752 case Type.object: return 0; 753 } 754 } else static if( is(T : long) ){ 755 final switch( m_type ){ 756 case Type.undefined: return 0; 757 case Type.null_: return 0; 758 case Type.bool_: return m_bool ? 1 : 0; 759 case Type.int_: return cast(T)m_int; 760 case Type.bigInt: return cast(T)bigIntToLong(); 761 case Type.float_: return cast(T)m_float; 762 case Type..string: return cast(T).to!long(cast(string)m_string); 763 case Type.array: return 0; 764 case Type.object: return 0; 765 } 766 } else static if( is(T == string) ){ 767 switch( m_type ){ 768 default: return toString(); 769 case Type..string: return m_string; 770 } 771 } else static if( is(T == Json[]) ){ 772 switch( m_type ){ 773 default: return Json([this]); 774 case Type.array: return m_array; 775 } 776 } else static if( is(T == Json[string]) ){ 777 switch( m_type ){ 778 default: return Json(["value": this]); 779 case Type.object: return m_object; 780 } 781 } else static if( is(T == BigInt) ){ 782 final switch( m_type ){ 783 case Type.undefined: return BigInt(0); 784 case Type.null_: return BigInt(0); 785 case Type.bool_: return BigInt(m_bool ? 1 : 0); 786 case Type.int_: return BigInt(m_int); 787 case Type.bigInt: return m_bigInt; 788 case Type.float_: return BigInt(cast(long)m_float); 789 case Type..string: return BigInt(.to!long(m_string)); 790 case Type.array: return BigInt(0); 791 case Type.object: return BigInt(0); 792 } 793 } else static if (is(T == JSONValue)) { 794 return cast(JSONValue)this; 795 } else static assert(0, "JSON can only be cast to (bool, long, std.bigint.BigInt, double, string, Json[] or Json[string]. Not "~T.stringof~"."); 796 } 797 798 /** 799 Performs unary operations on the JSON value. 800 801 The following operations are supported for each type: 802 803 $(DL 804 $(DT Null) $(DD none) 805 $(DT Bool) $(DD ~) 806 $(DT Int) $(DD +, -, ++, --) 807 $(DT Float) $(DD +, -, ++, --) 808 $(DT String) $(DD none) 809 $(DT Array) $(DD none) 810 $(DT Object) $(DD none) 811 ) 812 */ 813 Json opUnary(string op)() 814 const @trusted { 815 static if( op == "~" ){ 816 checkType!bool(); 817 return Json(~m_bool); 818 } else static if( op == "+" || op == "-" || op == "++" || op == "--" ){ 819 checkType!(BigInt, long, double)("unary "~op); 820 if( m_type == Type.int_ ) mixin("return Json("~op~"m_int);"); 821 else if( m_type == Type.bigInt ) mixin("return Json("~op~"m_bigInt);"); 822 else if( m_type == Type.float_ ) mixin("return Json("~op~"m_float);"); 823 else assert(false); 824 } else static assert(0, "Unsupported operator '"~op~"' for type JSON."); 825 } 826 /** 827 Performs binary operations between JSON values. 828 829 The two JSON values must be of the same run time type or a JSONException 830 will be thrown. Only the operations listed are allowed for each of the 831 types. 832 833 $(DL 834 $(DT Null) $(DD none) 835 $(DT Bool) $(DD &&, ||) 836 $(DT Int) $(DD +, -, *, /, %) 837 $(DT Float) $(DD +, -, *, /, %) 838 $(DT String) $(DD ~) 839 $(DT Array) $(DD ~) 840 $(DT Object) $(DD in) 841 ) 842 */ 843 Json opBinary(string op)(ref const(Json) other) 844 const @trusted { 845 enforceJson(m_type == other.m_type, "Binary operation '"~op~"' between "~m_type.enumToString~" and "~other.m_type.enumToString~" JSON objects."); 846 static if( op == "&&" ){ 847 checkType!(bool)(op); 848 return Json(m_bool && other.m_bool); 849 } else static if( op == "||" ){ 850 checkType!(bool)(op); 851 return Json(m_bool || other.m_bool); 852 } else static if( op == "+" ){ 853 checkType!(BigInt, long, double)(op); 854 if( m_type == Type.int_ ) return Json(m_int + other.m_int); 855 else if( m_type == Type.bigInt ) return Json(() @trusted { return m_bigInt + other.m_bigInt; } ()); 856 else if( m_type == Type.float_ ) return Json(m_float + other.m_float); 857 else assert(false); 858 } else static if( op == "-" ){ 859 checkType!(BigInt, long, double)(op); 860 if( m_type == Type.int_ ) return Json(m_int - other.m_int); 861 else if( m_type == Type.bigInt ) return Json(() @trusted { return m_bigInt - other.m_bigInt; } ()); 862 else if( m_type == Type.float_ ) return Json(m_float - other.m_float); 863 else assert(false); 864 } else static if( op == "*" ){ 865 checkType!(BigInt, long, double)(op); 866 if( m_type == Type.int_ ) return Json(m_int * other.m_int); 867 else if( m_type == Type.bigInt ) return Json(() @trusted { return m_bigInt * other.m_bigInt; } ()); 868 else if( m_type == Type.float_ ) return Json(m_float * other.m_float); 869 else assert(false); 870 } else static if( op == "/" ){ 871 checkType!(BigInt, long, double)(op); 872 if( m_type == Type.int_ ) return Json(m_int / other.m_int); 873 else if( m_type == Type.bigInt ) return Json(() @trusted { return m_bigInt / other.m_bigInt; } ()); 874 else if( m_type == Type.float_ ) return Json(m_float / other.m_float); 875 else assert(false); 876 } else static if( op == "%" ){ 877 checkType!(BigInt, long, double)(op); 878 if( m_type == Type.int_ ) return Json(m_int % other.m_int); 879 else if( m_type == Type.bigInt ) return Json(() @trusted { return m_bigInt % other.m_bigInt; } ()); 880 else if( m_type == Type.float_ ) return Json(m_float % other.m_float); 881 else assert(false); 882 } else static if( op == "~" ){ 883 checkType!(string, Json[])(op); 884 if( m_type == Type..string ) return Json(m_string ~ other.m_string); 885 else if (m_type == Type.array) return Json(m_array ~ other.m_array); 886 else assert(false); 887 } else static assert(0, "Unsupported operator '"~op~"' for type JSON."); 888 } 889 /// ditto 890 Json opBinary(string op)(Json other) @trusted 891 if( op == "~" ) 892 { 893 static if( op == "~" ){ 894 checkType!(string, Json[])(op); 895 if( m_type == Type..string ) return Json(m_string ~ other.m_string); 896 else if( m_type == Type.array ) return Json(m_array ~ other.m_array); 897 else assert(false); 898 } else static assert(0, "Unsupported operator '"~op~"' for type JSON."); 899 } 900 /// ditto 901 void opOpAssign(string op)(Json other) @trusted 902 if (op == "+" || op == "-" || op == "*" || op == "/" || op == "%" || op =="~") 903 { 904 enforceJson(m_type == other.m_type || op == "~" && m_type == Type.array, 905 "Binary operation '"~op~"=' between "~m_type.enumToString~" and "~other.m_type.enumToString~" JSON objects."); 906 static if( op == "+" ){ 907 if( m_type == Type.int_ ) m_int += other.m_int; 908 else if( m_type == Type.bigInt ) m_bigInt += other.m_bigInt; 909 else if( m_type == Type.float_ ) m_float += other.m_float; 910 else enforceJson(false, "'+=' only allowed for scalar types, not "~m_type.enumToString~"."); 911 } else static if( op == "-" ){ 912 if( m_type == Type.int_ ) m_int -= other.m_int; 913 else if( m_type == Type.bigInt ) m_bigInt -= other.m_bigInt; 914 else if( m_type == Type.float_ ) m_float -= other.m_float; 915 else enforceJson(false, "'-=' only allowed for scalar types, not "~m_type.enumToString~"."); 916 } else static if( op == "*" ){ 917 if( m_type == Type.int_ ) m_int *= other.m_int; 918 else if( m_type == Type.bigInt ) m_bigInt *= other.m_bigInt; 919 else if( m_type == Type.float_ ) m_float *= other.m_float; 920 else enforceJson(false, "'*=' only allowed for scalar types, not "~m_type.enumToString~"."); 921 } else static if( op == "/" ){ 922 if( m_type == Type.int_ ) m_int /= other.m_int; 923 else if( m_type == Type.bigInt ) m_bigInt /= other.m_bigInt; 924 else if( m_type == Type.float_ ) m_float /= other.m_float; 925 else enforceJson(false, "'/=' only allowed for scalar types, not "~m_type.enumToString~"."); 926 } else static if( op == "%" ){ 927 if( m_type == Type.int_ ) m_int %= other.m_int; 928 else if( m_type == Type.bigInt ) m_bigInt %= other.m_bigInt; 929 else if( m_type == Type.float_ ) m_float %= other.m_float; 930 else enforceJson(false, "'%=' only allowed for scalar types, not "~m_type.enumToString~"."); 931 } else static if( op == "~" ){ 932 if (m_type == Type..string) m_string ~= other.m_string; 933 else if (m_type == Type.array) { 934 if (other.m_type == Type.array) m_array ~= other.m_array; 935 else appendArrayElement(other); 936 } else enforceJson(false, "'~=' only allowed for string and array types, not "~m_type.enumToString~"."); 937 } else static assert(0, "Unsupported operator '"~op~"=' for type JSON."); 938 } 939 /// ditto 940 void opOpAssign(string op, T)(T other) 941 if (!is(T == Json) && is(typeof(Json(other)))) 942 { 943 opOpAssign!op(Json(other)); 944 } 945 /// ditto 946 Json opBinary(string op)(bool other) const { checkType!bool(); mixin("return Json(m_bool "~op~" other);"); } 947 /// ditto 948 Json opBinary(string op)(long other) const @trusted 949 { 950 checkType!(long, BigInt)(); 951 if (m_type == Type.bigInt) 952 mixin("return Json(m_bigInt "~op~" other);"); 953 else 954 mixin("return Json(m_int "~op~" other);"); 955 } 956 /// ditto 957 Json opBinary(string op)(BigInt other) const @trusted 958 { 959 checkType!(long, BigInt)(); 960 if (m_type == Type.bigInt) 961 mixin("return Json(m_bigInt "~op~" other);"); 962 else 963 mixin("return Json(m_int "~op~" other);"); 964 } 965 /// ditto 966 Json opBinary(string op)(double other) const { checkType!double(); mixin("return Json(m_float "~op~" other);"); } 967 /// ditto 968 Json opBinary(string op)(string other) const @trusted { checkType!string(); mixin("return Json(m_string "~op~" other);"); } 969 /// ditto 970 Json opBinary(string op)(Json[] other) @trusted { checkType!(Json[])(); mixin("return Json(m_array "~op~" other);"); } 971 /// ditto 972 Json opBinaryRight(string op)(bool other) const { checkType!bool(); mixin("return Json(other "~op~" m_bool);"); } 973 /// ditto 974 Json opBinaryRight(string op)(long other) const @trusted 975 { 976 checkType!(long, BigInt)(); 977 if (m_type == Type.bigInt) 978 mixin("return Json(other "~op~" m_bigInt);"); 979 else 980 mixin("return Json(other "~op~" m_int);"); 981 } 982 /// ditto 983 Json opBinaryRight(string op)(BigInt other) const @trusted 984 { 985 checkType!(long, BigInt)(); 986 if (m_type == Type.bigInt) 987 mixin("return Json(other "~op~" m_bigInt);"); 988 else 989 mixin("return Json(other "~op~" m_int);"); 990 } 991 /// ditto 992 Json opBinaryRight(string op)(double other) const { checkType!double(); mixin("return Json(other "~op~" m_float);"); } 993 /// ditto 994 Json opBinaryRight(string op)(string other) const @trusted if(op == "~") 995 { 996 checkType!string(); 997 return Json(other ~ m_string); 998 } 999 /// ditto 1000 Json opBinaryRight(string op)(Json[] other) @trusted { checkType!(Json[])(); mixin("return Json(other "~op~" m_array);"); } 1001 1002 1003 /** Checks wheter a particular key is set and returns a pointer to it. 1004 1005 For field that don't exist or have a type of `Type.undefined`, 1006 the `in` operator will return `null`. 1007 */ 1008 inout(Json)* opBinaryRight(string op)(string other) inout @trusted 1009 if(op == "in") 1010 { 1011 checkType!(Json[string])(); 1012 auto pv = other in m_object; 1013 if (!pv) return null; 1014 if (pv.type == Type.undefined) return null; 1015 return pv; 1016 } 1017 1018 /// 1019 @safe unittest { 1020 auto j = Json.emptyObject; 1021 j["a"] = "foo"; 1022 j["b"] = Json.undefined; 1023 1024 assert("a" in j); 1025 assert(("a" in j).get!string == "foo"); 1026 assert("b" !in j); 1027 assert("c" !in j); 1028 } 1029 1030 1031 /** 1032 * The append operator will append arrays. This method always appends it's argument as an array element, so nested arrays can be created. 1033 */ 1034 void appendArrayElement(Json element) 1035 @trusted { 1036 enforceJson(m_type == Type.array, "'appendArrayElement' only allowed for array types, not "~m_type.enumToString~"."); 1037 m_array ~= element; 1038 } 1039 1040 /** 1041 Compares two JSON values for equality. 1042 1043 If the two values have different types, they are considered unequal. 1044 This differs with ECMA script, which performs a type conversion before 1045 comparing the values. 1046 */ 1047 1048 bool opEquals(ref const Json other) 1049 const @trusted { 1050 if( m_type != other.m_type ) return false; 1051 final switch(m_type){ 1052 case Type.undefined: return false; 1053 case Type.null_: return true; 1054 case Type.bool_: return m_bool == other.m_bool; 1055 case Type.int_: return m_int == other.m_int; 1056 case Type.bigInt: return m_bigInt == other.m_bigInt; 1057 case Type.float_: return m_float == other.m_float; 1058 case Type..string: return m_string == other.m_string; 1059 case Type.array: return m_array == other.m_array; 1060 case Type.object: return m_object == other.m_object; 1061 } 1062 } 1063 /// ditto 1064 bool opEquals(const Json other) const { return opEquals(other); } 1065 /// ditto 1066 bool opEquals(typeof(null)) const { return m_type == Type.null_; } 1067 /// ditto 1068 bool opEquals(bool v) const { return m_type == Type.bool_ && m_bool == v; } 1069 /// ditto 1070 bool opEquals(int v) const @trusted { return (m_type == Type.int_ && m_int == v) || (m_type == Type.bigInt && m_bigInt == v); } 1071 /// ditto 1072 bool opEquals(long v) const @trusted { return (m_type == Type.int_ && m_int == v) || (m_type == Type.bigInt && m_bigInt == v); } 1073 /// ditto 1074 bool opEquals(BigInt v) const @trusted { return (m_type == Type.int_ && m_int == v) || (m_type == Type.bigInt && m_bigInt == v); } 1075 /// ditto 1076 bool opEquals(double v) const { return m_type == Type.float_ && m_float == v; } 1077 /// ditto 1078 bool opEquals(string v) const @trusted { return m_type == Type..string && m_string == v; } 1079 1080 /** 1081 Compares two JSON values. 1082 1083 If the types of the two values differ, the value with the smaller type 1084 id is considered the smaller value. This differs from ECMA script, which 1085 performs a type conversion before comparing the values. 1086 1087 JSON values of type Object cannot be compared and will throw an 1088 exception. 1089 */ 1090 int opCmp(ref const Json other) 1091 const @trusted { 1092 if( m_type != other.m_type ) return m_type < other.m_type ? -1 : 1; 1093 final switch(m_type){ 1094 case Type.undefined: return 0; 1095 case Type.null_: return 0; 1096 case Type.bool_: return m_bool < other.m_bool ? -1 : m_bool == other.m_bool ? 0 : 1; 1097 case Type.int_: return m_int < other.m_int ? -1 : m_int == other.m_int ? 0 : 1; 1098 case Type.bigInt: return () @trusted { return m_bigInt < other.m_bigInt; } () ? -1 : m_bigInt == other.m_bigInt ? 0 : 1; 1099 case Type.float_: return m_float < other.m_float ? -1 : m_float == other.m_float ? 0 : 1; 1100 case Type..string: return m_string < other.m_string ? -1 : m_string == other.m_string ? 0 : 1; 1101 case Type.array: return m_array < other.m_array ? -1 : m_array == other.m_array ? 0 : 1; 1102 case Type.object: 1103 enforceJson(false, "JSON objects cannot be compared."); 1104 assert(false); 1105 } 1106 } 1107 1108 alias opDollar = length; 1109 1110 /** 1111 Returns the type id corresponding to the given D type. 1112 */ 1113 static @property Type typeId(T)() { 1114 static if( is(T == typeof(null)) ) return Type.null_; 1115 else static if( is(T == bool) ) return Type.bool_; 1116 else static if( is(T == double) ) return Type.float_; 1117 else static if( is(T == float) ) return Type.float_; 1118 else static if( is(T : long) ) return Type.int_; 1119 else static if( is(T == string) ) return Type..string; 1120 else static if( is(T == UUID) ) return Type..string; 1121 else static if( is(T == Json[]) ) return Type.array; 1122 else static if( is(T == Json[string]) ) return Type.object; 1123 else static if( is(T == BigInt) ) return Type.bigInt; 1124 else static assert(false, "Unsupported JSON type '"~T.stringof~"'. Only bool, long, std.bigint.BigInt, double, string, Json[] and Json[string] are allowed."); 1125 } 1126 1127 /** 1128 Returns the JSON object as a string. 1129 1130 For large JSON values use writeJsonString instead as this function will store the whole string 1131 in memory, whereas writeJsonString writes it out bit for bit. 1132 1133 See_Also: writeJsonString, toPrettyString 1134 */ 1135 string toString() 1136 const @trusted { 1137 // DMD BUG: this should actually be all @safe, but for some reason 1138 // @safe inference for writeJsonString doesn't work. 1139 auto ret = appender!string(); 1140 writeJsonString(ret, this); 1141 return ret.data; 1142 } 1143 /// ditto 1144 void toString(scope void delegate(scope const(char)[]) @safe sink, FormatSpec!char fmt) 1145 @trusted { 1146 // DMD BUG: this should actually be all @safe, but for some reason 1147 // @safe inference for writeJsonString doesn't work. 1148 static struct DummyRangeS { 1149 void delegate(scope const(char)[]) @safe sink; 1150 void put(scope const(char)[] str) @safe { sink(str); } 1151 void put(char ch) @trusted { sink((&ch)[0 .. 1]); } 1152 } 1153 auto r = DummyRangeS(sink); 1154 writeJsonString(r, this); 1155 } 1156 /// ditto 1157 void toString(scope void delegate(scope const(char)[]) @system sink, FormatSpec!char fmt) 1158 @system { 1159 // DMD BUG: this should actually be all @safe, but for some reason 1160 // @safe inference for writeJsonString doesn't work. 1161 static struct DummyRange { 1162 void delegate(scope const(char)[]) sink; 1163 @trusted: 1164 void put(scope const(char)[] str) { sink(str); } 1165 void put(char ch) { sink((&ch)[0 .. 1]); } 1166 } 1167 auto r = DummyRange(sink); 1168 writeJsonString(r, this); 1169 } 1170 /// ditto 1171 deprecated("Use a `scope` argument for the `sink` delegate") 1172 void toString(scope void delegate(const(char)[]) @safe sink, FormatSpec!char fmt) 1173 @trusted { 1174 // DMD BUG: this should actually be all @safe, but for some reason 1175 // @safe inference for writeJsonString doesn't work. 1176 static struct DummyRangeS { 1177 void delegate(const(char)[]) @safe sink; 1178 void put(scope const(char)[] str) @safe { sink(str); } 1179 void put(char ch) @trusted { sink((&ch)[0 .. 1]); } 1180 } 1181 auto r = DummyRangeS(sink); 1182 writeJsonString(r, this); 1183 } 1184 /// ditto 1185 void toString(scope void delegate(const(char)[]) @system sink, FormatSpec!char fmt) 1186 @system { 1187 // DMD BUG: this should actually be all @safe, but for some reason 1188 // @safe inference for writeJsonString doesn't work. 1189 static struct DummyRange { 1190 void delegate(const(char)[]) sink; 1191 @trusted: 1192 void put(scope const(char)[] str) { sink(str); } 1193 void put(char ch) { sink((&ch)[0 .. 1]); } 1194 } 1195 auto r = DummyRange(sink); 1196 writeJsonString(r, this); 1197 } 1198 1199 /** 1200 Returns the JSON object as a "pretty" string. 1201 1202 --- 1203 auto json = Json(["foo": Json("bar")]); 1204 writeln(json.toPrettyString()); 1205 1206 // output: 1207 // { 1208 // "foo": "bar" 1209 // } 1210 --- 1211 1212 Params: 1213 level = Specifies the base amount of indentation for the output. Indentation is always 1214 done using tab characters. 1215 1216 See_Also: writePrettyJsonString, toString 1217 */ 1218 string toPrettyString(int level = 0) 1219 const @trusted { 1220 auto ret = appender!string(); 1221 writePrettyJsonString(ret, this, level); 1222 return ret.data; 1223 } 1224 1225 private void checkType(TYPES...)(string op = null) 1226 const { 1227 bool matched = false; 1228 foreach (T; TYPES) if (m_type == typeId!T) matched = true; 1229 if (matched) return; 1230 1231 string name; 1232 version (VibeJsonFieldNames) { 1233 if (m_name.length) name = m_name ~ " of type " ~ m_type.enumToString; 1234 else name = "JSON of type " ~ m_type.enumToString; 1235 } else name = "JSON of type " ~ m_type.enumToString; 1236 1237 string expected; 1238 static if (TYPES.length == 1) expected = typeId!(TYPES[0]).enumToString; 1239 else { 1240 foreach (T; TYPES) { 1241 if (expected.length > 0) expected ~= ", "; 1242 expected ~= typeId!T.enumToString; 1243 } 1244 } 1245 1246 if (!op.length) throw new JSONException(format("Got %s, expected %s.", name, expected)); 1247 else throw new JSONException(format("Got %s, expected %s for %s.", name, expected, op)); 1248 } 1249 1250 private void initBigInt() 1251 nothrow @trusted { 1252 // BigInt is a struct, and it has a special BigInt.init value, which differs from null. 1253 m_bigInt = BigInt.init; 1254 } 1255 1256 private void runDestructors() 1257 nothrow @trusted { 1258 if (m_type != Type.bigInt) 1259 { 1260 zeroFields; 1261 return; 1262 } 1263 1264 BigInt init_; 1265 // After swaping, init_ contains the real number from Json, and it 1266 // will be destroyed when this function is finished. 1267 // m_bigInt now contains static BigInt.init value and destruction may 1268 // be ommited for it. 1269 swap(init_, m_bigInt); 1270 } 1271 1272 private long bigIntToLong() inout @trusted 1273 { 1274 assert(m_type == Type.bigInt, format("Converting non-bigInt type with bitIntToLong!?: %s", (cast(Type)m_type).enumToString)); 1275 enforceJson(m_bigInt >= long.min && m_bigInt <= long.max, "Number out of range while converting BigInt("~format("%d", m_bigInt)~") to long."); 1276 return m_bigInt.toLong(); 1277 } 1278 1279 /*invariant() 1280 { 1281 assert(m_type >= Type.Undefined && m_type <= Type.Object); 1282 }*/ 1283 } 1284 1285 @safe unittest { // issue #1234 - @safe toString 1286 auto j = Json(true); 1287 j.toString((scope str) @safe {}, FormatSpec!char("s")); 1288 assert(j.toString() == "true"); 1289 } 1290 1291 1292 /******************************************************************************/ 1293 /* public functions */ 1294 /******************************************************************************/ 1295 1296 /** 1297 Parses the given range as a JSON string and returns the corresponding Json object. 1298 1299 The range is shrunk during parsing, leaving any remaining text that is not part of 1300 the JSON contents. 1301 1302 Throws a JSONException if any parsing error occured. 1303 */ 1304 Json parseJson(R)(ref R range, scope int* line = null, string filename = null) 1305 if (isForwardRange!R) 1306 { 1307 Json ret; 1308 enforceJson(!range.empty, "JSON string is empty.", filename, 0); 1309 1310 skipWhitespace(range, line); 1311 1312 enforceJson(!range.empty, "JSON string contains only whitespaces.", filename, 0); 1313 1314 version(JsonLineNumbers) { 1315 int curline = line ? *line : 0; 1316 } 1317 1318 bool minus = false; 1319 switch( range.front ){ 1320 case 'f': 1321 enforceJson(range.save.dropOne.startsWith("alse"), 1322 "Expected 'false', got '"~range.take(5).to!string~"'.", filename, line); 1323 range.popFrontN(5); 1324 ret = false; 1325 break; 1326 case 'n': 1327 enforceJson(range.save.dropOne.startsWith("ull"), 1328 "Expected 'null', got '"~range.take(4).to!string~"'.", filename, line); 1329 range.popFrontN(4); 1330 ret = null; 1331 break; 1332 case 't': 1333 enforceJson(range.save.dropOne.startsWith("rue"), 1334 "Expected 'true', got '"~range.take(4).to!string~"'.", filename, line); 1335 range.popFrontN(4); 1336 ret = true; 1337 break; 1338 1339 case '-': 1340 case '0': .. case '9': 1341 bool is_long_overflow; 1342 bool is_float; 1343 auto num = skipNumber(range, is_float, is_long_overflow); 1344 if( is_float ) { 1345 ret = to!double(num); 1346 } else if (is_long_overflow) { 1347 ret = () @trusted { return BigInt(num.to!string); } (); 1348 } else { 1349 ret = to!long(num); 1350 } 1351 break; 1352 case '\"': 1353 ret = skipJsonString(range); 1354 break; 1355 case '[': 1356 auto arr = appender!(Json[]); 1357 range.popFront(); 1358 while (true) { 1359 skipWhitespace(range, line); 1360 enforceJson(!range.empty, "Missing ']' before EOF.", filename, line); 1361 if(range.front == ']') break; 1362 arr ~= parseJson(range, line, filename); 1363 skipWhitespace(range, line); 1364 enforceJson(!range.empty, "Missing ']' before EOF.", filename, line); 1365 enforceJson(range.front == ',' || range.front == ']', 1366 format("Expected ']' or ',' - got '%s'.", range.front), filename, line); 1367 if( range.front == ']' ) break; 1368 else range.popFront(); 1369 } 1370 range.popFront(); 1371 ret = arr.data; 1372 break; 1373 case '{': 1374 Json[string] obj; 1375 range.popFront(); 1376 while (true) { 1377 skipWhitespace(range, line); 1378 enforceJson(!range.empty, "Missing '}' before EOF.", filename, line); 1379 if(range.front == '}') break; 1380 string key = skipJsonString(range); 1381 skipWhitespace(range, line); 1382 enforceJson(range.startsWith(":"), "Expected ':' for key '" ~ key ~ "'", filename, line); 1383 range.popFront(); 1384 skipWhitespace(range, line); 1385 Json itm = parseJson(range, line, filename); 1386 obj[key] = itm; 1387 skipWhitespace(range, line); 1388 enforceJson(!range.empty, "Missing '}' before EOF.", filename, line); 1389 enforceJson(range.front == ',' || range.front == '}', 1390 format("Expected '}' or ',' - got '%s'.", range.front), filename, line); 1391 if (range.front == '}') break; 1392 else range.popFront(); 1393 } 1394 range.popFront(); 1395 ret = obj; 1396 break; 1397 default: 1398 enforceJson(false, format("Expected valid JSON token, got '%s'.", range.take(12)), filename, line); 1399 assert(false); 1400 } 1401 1402 assert(ret.type != Json.Type.undefined); 1403 version(JsonLineNumbers) ret.line = curline; 1404 return ret; 1405 } 1406 1407 1408 unittest { // ensure parseJson works with a generic forward range 1409 static struct R { 1410 const(char)[] text; 1411 1412 @property char front() { return text[0]; } 1413 @property R save() { return this; } 1414 @property bool empty() const { return text.length == 0; } 1415 void popFront() { text = text[1 .. $]; } 1416 } 1417 1418 auto r = R(`{"i":42, "s": "foo"}`); 1419 auto j = parseJson(r); 1420 assert(j["i"] == 42); 1421 assert(j["s"] == "foo"); 1422 } 1423 1424 1425 /** 1426 Parses the given JSON string and returns the corresponding Json object. 1427 1428 Throws a JSONException if any parsing error occurs. 1429 */ 1430 Json parseJsonString(string str, string filename = null) 1431 @safe { 1432 auto strcopy = str; 1433 int line = 0; 1434 auto ret = parseJson(strcopy, () @trusted { return &line; } (), filename); 1435 enforceJson(strcopy.strip().length == 0, "Expected end of string after JSON value.", filename, line); 1436 return ret; 1437 } 1438 1439 @safe unittest { 1440 // These currently don't work at compile time 1441 assert(parseJsonString("17559991181826658461") == Json(BigInt(17559991181826658461UL))); 1442 assert(parseJsonString("99999999999999999999999999") == () @trusted { return Json(BigInt("99999999999999999999999999")); } ()); 1443 auto json = parseJsonString(`{"hey": "This is @à test éhééhhéhéé !%/??*&?\ud83d\udcec"}`); 1444 assert(json.toPrettyString() == parseJsonString(json.toPrettyString()).toPrettyString()); 1445 1446 bool test() { 1447 assert(parseJsonString("null") == Json(null)); 1448 assert(parseJsonString("true") == Json(true)); 1449 assert(parseJsonString("false") == Json(false)); 1450 assert(parseJsonString("1") == Json(1)); 1451 assert(parseJsonString("2.0") == Json(2.0)); 1452 assert(parseJsonString("\"test\"") == Json("test")); 1453 assert(parseJsonString("[1, 2, 3]") == Json([Json(1), Json(2), Json(3)])); 1454 assert(parseJsonString("{\"a\": 1}") == Json(["a": Json(1)])); 1455 assert(parseJsonString(`"\\\/\b\f\n\r\t\u1234"`).get!string == "\\/\b\f\n\r\t\u1234"); 1456 1457 return true; 1458 } 1459 1460 // Run at compile time and runtime 1461 assert(test()); 1462 static assert(test()); 1463 } 1464 1465 @safe nothrow unittest { 1466 bool test() { 1467 try parseJsonString(" \t\n "); 1468 catch (Exception e) assert(e.msg.endsWith("JSON string contains only whitespaces.")); 1469 try parseJsonString(`{"a": 1`); 1470 catch (Exception e) assert(e.msg.endsWith("Missing '}' before EOF.")); 1471 try parseJsonString(`{"a": 1 x`); 1472 catch (Exception e) assert(e.msg.endsWith("Expected '}' or ',' - got 'x'.")); 1473 try parseJsonString(`[1`); 1474 catch (Exception e) assert(e.msg.endsWith("Missing ']' before EOF.")); 1475 try parseJsonString(`[1 x`); 1476 catch (Exception e) assert(e.msg.endsWith("Expected ']' or ',' - got 'x'.")); 1477 1478 return true; 1479 } 1480 1481 // Run at compile time and runtime 1482 assert(test()); 1483 static assert(test()); 1484 } 1485 1486 /** 1487 Serializes the given value to JSON. 1488 1489 The following types of values are supported: 1490 1491 $(DL 1492 $(DT `Json`) $(DD Used as-is) 1493 $(DT `null`) $(DD Converted to `Json.Type.null_`) 1494 $(DT `bool`) $(DD Converted to `Json.Type.bool_`) 1495 $(DT `float`, `double`) $(DD Converted to `Json.Type.float_`) 1496 $(DT `short`, `ushort`, `int`, `uint`, `long`, `ulong`) $(DD Converted to `Json.Type.int_`) 1497 $(DT `BigInt`) $(DD Converted to `Json.Type.bigInt`) 1498 $(DT `string`) $(DD Converted to `Json.Type.string`) 1499 $(DT `T[]`) $(DD Converted to `Json.Type.array`) 1500 $(DT `T[string]`) $(DD Converted to `Json.Type.object`) 1501 $(DT `struct`) $(DD Converted to `Json.Type.object`) 1502 $(DT `class`) $(DD Converted to `Json.Type.object` or `Json.Type.null_`) 1503 ) 1504 1505 All entries of an array or an associative array, as well as all R/W properties and 1506 all public fields of a struct/class are recursively serialized using the same rules. 1507 1508 Fields ending with an underscore will have the last underscore stripped in the 1509 serialized output. This makes it possible to use fields with D keywords as their name 1510 by simply appending an underscore. 1511 1512 The following methods can be used to customize the serialization of structs/classes: 1513 1514 --- 1515 Json toJson() const; 1516 static T fromJson(Json src); 1517 1518 string toString() const; 1519 static T fromString(string src); 1520 --- 1521 1522 The methods will have to be defined in pairs. The first pair that is implemented by 1523 the type will be used for serialization (i.e. `toJson` overrides `toString`). 1524 1525 See_Also: `deserializeJson`, `vibe.data.serialization` 1526 */ 1527 Json serializeToJson(T)(auto ref T value) 1528 { 1529 return serialize!JsonSerializer(value); 1530 } 1531 /// ditto 1532 void serializeToJson(R, T)(R destination, auto ref T value) 1533 if (isOutputRange!(R, char) || isOutputRange!(R, ubyte)) 1534 { 1535 serialize!(JsonStringSerializer!R)(value, destination); 1536 } 1537 /// ditto 1538 string serializeToJsonString(T)(auto ref T value) 1539 { 1540 auto ret = appender!string; 1541 serializeToJson(ret, value); 1542 return ret.data; 1543 } 1544 1545 /// 1546 @safe unittest { 1547 struct Foo { 1548 int number; 1549 string str; 1550 } 1551 1552 Foo f; 1553 1554 f.number = 12; 1555 f.str = "hello"; 1556 1557 string json = serializeToJsonString(f); 1558 assert(json == `{"number":12,"str":"hello"}`); 1559 Json jsonval = serializeToJson(f); 1560 assert(jsonval.type == Json.Type.object); 1561 assert(jsonval["number"] == Json(12)); 1562 assert(jsonval["str"] == Json("hello")); 1563 } 1564 1565 1566 /** 1567 Serializes the given value to a pretty printed JSON string. 1568 1569 See_also: `serializeToJson`, `vibe.data.serialization` 1570 */ 1571 void serializeToPrettyJson(R, T)(R destination, auto ref T value) 1572 if (isOutputRange!(R, char) || isOutputRange!(R, ubyte)) 1573 { 1574 serialize!(JsonStringSerializer!(R, true))(value, destination); 1575 } 1576 /// ditto 1577 string serializeToPrettyJson(T)(auto ref T value) 1578 { 1579 auto ret = appender!string; 1580 serializeToPrettyJson(ret, value); 1581 return ret.data; 1582 } 1583 1584 /// 1585 @safe unittest { 1586 struct Foo { 1587 int number; 1588 string str; 1589 } 1590 1591 Foo f; 1592 f.number = 12; 1593 f.str = "hello"; 1594 1595 string json = serializeToPrettyJson(f); 1596 assert(json == 1597 `{ 1598 "number": 12, 1599 "str": "hello" 1600 }`); 1601 } 1602 1603 1604 /** 1605 Deserializes a JSON value into the destination variable. 1606 1607 The same types as for `serializeToJson()` are supported and handled inversely. 1608 1609 See_Also: `serializeToJson`, `serializeToJsonString`, `vibe.data.serialization` 1610 */ 1611 void deserializeJson(T)(ref T dst, Json src) 1612 { 1613 dst = deserializeJson!T(src); 1614 } 1615 /// ditto 1616 T deserializeJson(T)(Json src) 1617 { 1618 return deserialize!(JsonSerializer, T)(src); 1619 } 1620 /// ditto 1621 T deserializeJson(T, R)(R input) 1622 if (!is(R == Json) && isForwardRange!R) 1623 { 1624 return deserialize!(JsonStringSerializer!R, T)(input); 1625 } 1626 1627 /// 1628 @safe unittest { 1629 struct Foo { 1630 int number; 1631 string str; 1632 } 1633 Foo f = deserializeJson!Foo(`{"number": 12, "str": "hello"}`); 1634 assert(f.number == 12); 1635 assert(f.str == "hello"); 1636 } 1637 1638 @safe unittest { 1639 import std.stdio; 1640 enum Foo : string { k = "test" } 1641 enum Boo : int { l = 5 } 1642 static struct S { float a; double b; bool c; int d; string e; byte f; ubyte g; long h; ulong i; float[] j; Foo k; Boo l; } 1643 immutable S t = {1.5, -3.0, true, int.min, "Test", -128, 255, long.min, ulong.max, [1.1, 1.2, 1.3], Foo.k, Boo.l}; 1644 S u; 1645 deserializeJson(u, serializeToJson(t)); 1646 assert(t.a == u.a); 1647 assert(t.b == u.b); 1648 assert(t.c == u.c); 1649 assert(t.d == u.d); 1650 assert(t.e == u.e); 1651 assert(t.f == u.f); 1652 assert(t.g == u.g); 1653 assert(t.h == u.h); 1654 assert(t.i == u.i); 1655 assert(t.j == u.j); 1656 assert(t.k == u.k); 1657 assert(t.l == u.l); 1658 } 1659 1660 @safe unittest 1661 { 1662 assert(uint.max == serializeToJson(uint.max).deserializeJson!uint); 1663 assert(ulong.max == serializeToJson(ulong.max).deserializeJson!ulong); 1664 } 1665 1666 @safe unittest { 1667 static struct A { int value; static A fromJson(Json val) @safe { return A(val.get!int); } Json toJson() const @safe { return Json(value); } } 1668 static struct C { int value; static C fromString(string val) @safe { return C(val.to!int); } string toString() const @safe { return value.to!string; } } 1669 static struct D { int value; } 1670 1671 assert(serializeToJson(const A(123)) == Json(123)); 1672 assert(serializeToJson(A(123)) == Json(123)); 1673 assert(serializeToJson(const C(123)) == Json("123")); 1674 assert(serializeToJson(C(123)) == Json("123")); 1675 assert(serializeToJson(const D(123)) == serializeToJson(["value": 123])); 1676 assert(serializeToJson(D(123)) == serializeToJson(["value": 123])); 1677 } 1678 1679 @safe unittest { 1680 auto d = Date(2001,1,1); 1681 deserializeJson(d, serializeToJson(Date.init)); 1682 assert(d == Date.init); 1683 deserializeJson(d, serializeToJson(Date(2001,1,1))); 1684 assert(d == Date(2001,1,1)); 1685 struct S { immutable(int)[] x; } 1686 S s; 1687 deserializeJson(s, serializeToJson(S([1,2,3]))); 1688 assert(s == S([1,2,3])); 1689 struct T { 1690 @optional S s; 1691 @optional int i; 1692 @optional float f_; // underscore strip feature 1693 @optional double d; 1694 @optional string str; 1695 } 1696 auto t = T(S([1,2,3])); 1697 deserializeJson(t, parseJsonString(`{ "s" : null, "i" : null, "f" : null, "d" : null, "str" : null }`)); 1698 assert(text(t) == text(T())); 1699 } 1700 1701 @safe unittest { 1702 static class C { 1703 @safe: 1704 int a; 1705 private int _b; 1706 @property int b() const { return _b; } 1707 @property void b(int v) { _b = v; } 1708 1709 @property int test() const { return 10; } 1710 1711 void test2() {} 1712 } 1713 C c = new C; 1714 c.a = 1; 1715 c.b = 2; 1716 1717 C d; 1718 deserializeJson(d, serializeToJson(c)); 1719 assert(c.a == d.a); 1720 assert(c.b == d.b); 1721 } 1722 1723 @safe unittest { 1724 static struct C { @safe: int value; static C fromString(string val) { return C(val.to!int); } string toString() const { return value.to!string; } } 1725 enum Color { Red, Green, Blue } 1726 { 1727 static class T { 1728 @safe: 1729 string[Color] enumIndexedMap; 1730 string[C] stringableIndexedMap; 1731 this() { 1732 enumIndexedMap = [ Color.Red : "magenta", Color.Blue : "deep blue" ]; 1733 stringableIndexedMap = [ C(42) : "forty-two" ]; 1734 } 1735 } 1736 1737 T original = new T; 1738 original.enumIndexedMap[Color.Green] = "olive"; 1739 T other; 1740 deserializeJson(other, serializeToJson(original)); 1741 assert(serializeToJson(other) == serializeToJson(original)); 1742 } 1743 { 1744 static struct S { 1745 string[Color] enumIndexedMap; 1746 string[C] stringableIndexedMap; 1747 } 1748 1749 S *original = new S; 1750 original.enumIndexedMap = [ Color.Red : "magenta", Color.Blue : "deep blue" ]; 1751 original.enumIndexedMap[Color.Green] = "olive"; 1752 original.stringableIndexedMap = [ C(42) : "forty-two" ]; 1753 S other; 1754 deserializeJson(other, serializeToJson(original)); 1755 assert(serializeToJson(other) == serializeToJson(original)); 1756 } 1757 } 1758 1759 @safe unittest { 1760 import std.typecons : Nullable; 1761 1762 struct S { Nullable!int a, b; } 1763 S s; 1764 s.a = 2; 1765 1766 auto j = serializeToJson(s); 1767 assert(j["a"].type == Json.Type.int_); 1768 assert(j["b"].type == Json.Type.null_); 1769 1770 auto t = deserializeJson!S(j); 1771 assert(!t.a.isNull() && t.a == 2); 1772 assert(t.b.isNull()); 1773 } 1774 1775 @safe unittest { // #840 1776 int[2][2] nestedArray = 1; 1777 assert(nestedArray.serializeToJson.deserializeJson!(typeof(nestedArray)) == nestedArray); 1778 } 1779 1780 @safe unittest { // #1109 1781 static class C { 1782 @safe: 1783 int mem; 1784 this(int m) { mem = m; } 1785 static C fromJson(Json j) { return new C(j.get!int-1); } 1786 Json toJson() const { return Json(mem+1); } 1787 } 1788 const c = new C(13); 1789 assert(serializeToJson(c) == Json(14)); 1790 assert(deserializeJson!C(Json(14)).mem == 13); 1791 } 1792 1793 @safe unittest { // const and mutable json 1794 Json j = Json(1); 1795 const k = Json(2); 1796 assert(serializeToJson(j) == Json(1)); 1797 assert(serializeToJson(k) == Json(2)); 1798 } 1799 1800 @safe unittest { // issue #1660 - deserialize AA whose key type is string-based enum 1801 enum Foo: string 1802 { 1803 Bar = "bar", 1804 Buzz = "buzz" 1805 } 1806 1807 struct S { 1808 int[Foo] f; 1809 } 1810 1811 const s = S([Foo.Bar: 2000]); 1812 assert(serializeToJson(s)["f"] == Json([Foo.Bar: Json(2000)])); 1813 1814 auto j = Json.emptyObject; 1815 j["f"] = [Foo.Bar: Json(2000)]; 1816 assert(deserializeJson!S(j).f == [Foo.Bar: 2000]); 1817 } 1818 1819 @safe unittest { 1820 struct V { 1821 UUID v; 1822 } 1823 1824 const u = UUID("318d7a61-e41b-494e-90d3-0a99f5531bfe"); 1825 const s = `{"v":"318d7a61-e41b-494e-90d3-0a99f5531bfe"}`; 1826 auto j = Json(["v": Json(u)]); 1827 1828 const v = V(u); 1829 1830 assert(serializeToJson(v) == j); 1831 1832 j = Json.emptyObject; 1833 j["v"] = u; 1834 assert(deserializeJson!V(j).v == u); 1835 1836 assert(serializeToJsonString(v) == s); 1837 assert(deserializeJson!V(s).v == u); 1838 } 1839 1840 /** 1841 Serializer for a plain Json representation. 1842 1843 See_Also: vibe.data.serialization.serialize, vibe.data.serialization.deserialize, serializeToJson, deserializeJson 1844 */ 1845 struct JsonSerializer { 1846 template isJsonBasicType(T) { enum isJsonBasicType = std.traits.isNumeric!T || isBoolean!T || isSomeString!T || is(T == typeof(null)) || is(Unqual!T == UUID) || isJsonSerializable!T; } 1847 1848 template isSupportedValueType(T) { enum isSupportedValueType = isJsonBasicType!T || is(Unqual!T == Json) || is(Unqual!T == JSONValue); } 1849 1850 private { 1851 Json m_current; 1852 Json[] m_compositeStack; 1853 } 1854 1855 this(Json data) @safe { m_current = data; } 1856 1857 @disable this(this); 1858 1859 // 1860 // serialization 1861 // 1862 Json getSerializedResult() @safe { return m_current; } 1863 void beginWriteDictionary(Traits)() { m_compositeStack ~= Json.emptyObject; } 1864 void endWriteDictionary(Traits)() { m_current = m_compositeStack[$-1]; m_compositeStack.length--; } 1865 void beginWriteDictionaryEntry(Traits)(string name) {} 1866 void endWriteDictionaryEntry(Traits)(string name) { m_compositeStack[$-1][name] = m_current; } 1867 1868 void beginWriteArray(Traits)(size_t) { m_compositeStack ~= Json.emptyArray; } 1869 void endWriteArray(Traits)() { m_current = m_compositeStack[$-1]; m_compositeStack.length--; } 1870 void beginWriteArrayEntry(Traits)(size_t) {} 1871 void endWriteArrayEntry(Traits)(size_t) { m_compositeStack[$-1].appendArrayElement(m_current); } 1872 1873 void writeValue(Traits, T)(auto ref T value) 1874 if (!is(Unqual!T == Json)) 1875 { 1876 alias UT = Unqual!T; 1877 static if (is(UT == JSONValue)) { 1878 m_current = Json(value); 1879 } else static if (isJsonSerializable!UT) { 1880 static if (!__traits(compiles, () @safe { return value.toJson(); } ())) 1881 pragma(msg, "Non-@safe toJson/fromJson methods are deprecated - annotate "~UT.stringof~".toJson() with @safe."); 1882 m_current = () @trusted { return value.toJson(); } (); 1883 } else static if (isSomeString!T && !is(UT == string)) { 1884 writeValue!Traits(value.to!string); 1885 } else m_current = Json(value); 1886 } 1887 1888 void writeValue(Traits, T)(auto ref T value) if (is(T == Json)) { m_current = value; } 1889 void writeValue(Traits, T)(auto ref T value) if (!is(T == Json) && is(T : const(Json))) { m_current = value.clone; } 1890 1891 // 1892 // deserialization 1893 // 1894 void readDictionary(Traits)(scope void delegate(string) @safe field_handler) 1895 { 1896 enforceJson(m_current.type == Json.Type.object, "Expected JSON object, got "~m_current.type.enumToString); 1897 auto old = m_current; 1898 foreach (string key, value; m_current.get!(Json[string])) { 1899 if (value.type == Json.Type.undefined) { 1900 continue; 1901 } 1902 1903 m_current = value; 1904 field_handler(key); 1905 } 1906 m_current = old; 1907 } 1908 1909 void beginReadDictionaryEntry(Traits)(string name) {} 1910 void endReadDictionaryEntry(Traits)(string name) {} 1911 1912 void readArray(Traits)(scope void delegate(size_t) @safe size_callback, scope void delegate() @safe entry_callback) 1913 { 1914 enforceJson(m_current.type == Json.Type.array, "Expected JSON array, got "~m_current.type.enumToString); 1915 auto old = m_current; 1916 size_callback(m_current.length); 1917 foreach (ent; old.get!(Json[])) { 1918 m_current = ent; 1919 entry_callback(); 1920 } 1921 m_current = old; 1922 } 1923 1924 void beginReadArrayEntry(Traits)(size_t index) {} 1925 void endReadArrayEntry(Traits)(size_t index) {} 1926 1927 T readValue(Traits, T)() 1928 @safe { 1929 static if (is(T == Json)) return m_current; 1930 else static if (is(T == JSONValue)) return cast(JSONValue)m_current; 1931 else static if (isJsonSerializable!T) { 1932 static if (!__traits(compiles, () @safe { return T.fromJson(m_current); } ())) 1933 pragma(msg, "Non-@safe toJson/fromJson methods are deprecated - annotate "~T.stringof~".fromJson() with @safe."); 1934 return () @trusted { return T.fromJson(m_current); } (); 1935 } else static if (is(T == float) || is(T == double)) { 1936 switch (m_current.type) { 1937 default: return cast(T)m_current.get!long; 1938 case Json.Type.null_: goto case; 1939 case Json.Type.undefined: return T.nan; 1940 case Json.Type.float_: return cast(T)m_current.get!double; 1941 case Json.Type.bigInt: return cast(T)m_current.bigIntToLong(); 1942 } 1943 } else static if (is(T == const(char)[])) { 1944 return readValue!(Traits, string); 1945 } else static if (isSomeString!T && !is(T == string)) { 1946 return readValue!(Traits, string).to!T; 1947 } else static if (is(T == string)) { 1948 if (m_current.type == Json.Type.array) { // legacy support for pre-#2150 serialization results 1949 return () @trusted { // appender 1950 auto r = appender!string; 1951 foreach (s; m_current.get!(Json[])) 1952 r.put(s.get!string()); 1953 return r.data; 1954 } (); 1955 } else return m_current.get!T(); 1956 } else return m_current.get!T(); 1957 } 1958 1959 bool tryReadNull(Traits)() { return m_current.type == Json.Type.null_; } 1960 } 1961 1962 unittest { 1963 struct T { 1964 @optional string a; 1965 } 1966 1967 auto obj = Json.emptyObject; 1968 obj["a"] = Json.undefined; 1969 assert(obj.deserializeJson!T.a == ""); 1970 } 1971 1972 unittest { 1973 class C { this(Json j) {foo = j;} Json foo; } 1974 const C c = new C(Json(42)); 1975 assert(serializeToJson(c)["foo"].get!int == 42); 1976 } 1977 1978 /** 1979 Serializer for a range based plain JSON string representation. 1980 1981 See_Also: vibe.data.serialization.serialize, vibe.data.serialization.deserialize, serializeToJson, deserializeJson 1982 */ 1983 struct JsonStringSerializer(R, bool pretty = false) 1984 if (isInputRange!R || isOutputRange!(R, char)) 1985 { 1986 private { 1987 R m_range; 1988 size_t m_level = 0; 1989 } 1990 1991 template isJsonBasicType(T) { enum isJsonBasicType = std.traits.isNumeric!T || isBoolean!T || isSomeString!T || is(T == typeof(null)) || is(Unqual!T == UUID) || isJsonSerializable!T; } 1992 1993 template isSupportedValueType(T) { enum isSupportedValueType = isJsonBasicType!(Unqual!T) || is(Unqual!T == Json) || is(Unqual!T == JSONValue); } 1994 1995 this(R range) 1996 { 1997 m_range = range; 1998 } 1999 2000 @disable this(this); 2001 2002 // 2003 // serialization 2004 // 2005 static if (isOutputRange!(R, char)) { 2006 private { 2007 bool m_firstInComposite; 2008 } 2009 2010 void getSerializedResult() {} 2011 2012 void beginWriteDictionary(Traits)() { startComposite(); m_range.put('{'); } 2013 void endWriteDictionary(Traits)() { endComposite(); m_range.put("}"); } 2014 void beginWriteDictionaryEntry(Traits)(string name) 2015 { 2016 startCompositeEntry(); 2017 m_range.put('"'); 2018 m_range.jsonEscape(name); 2019 static if (pretty) m_range.put(`": `); 2020 else m_range.put(`":`); 2021 } 2022 void endWriteDictionaryEntry(Traits)(string name) {} 2023 2024 void beginWriteArray(Traits)(size_t) { startComposite(); m_range.put('['); } 2025 void endWriteArray(Traits)() { endComposite(); m_range.put(']'); } 2026 void beginWriteArrayEntry(Traits)(size_t) { startCompositeEntry(); } 2027 void endWriteArrayEntry(Traits)(size_t) {} 2028 2029 void writeValue(Traits, T)(in T value) 2030 { 2031 alias UT = Unqual!T; 2032 static if (is(T == typeof(null))) m_range.put("null"); 2033 else static if (is(UT == bool)) m_range.put(value ? "true" : "false"); 2034 else static if (is(UT : long)) m_range.formattedWriteFixed!32("%s", value); 2035 else static if (is(UT == BigInt)) () @trusted { 2036 static if (__VERSION__ < 2093) 2037 value.toString((scope s) { m_range.put(s); }, "%d"); 2038 else value.toString(m_range, "%d"); 2039 } (); 2040 else static if (is(UT : real)) value == value ? m_range.formattedWriteFixed!32("%.16g", value) : m_range.put("null"); 2041 else static if (is(UT : const(char)[])) { 2042 m_range.put('"'); 2043 m_range.jsonEscape(value); 2044 m_range.put('"'); 2045 } else static if (isSomeString!T) writeValue!Traits(value.to!string); // TODO: avoid memory allocation 2046 else static if (is(UT == UUID)) writeValue!Traits(value.toString()); 2047 else static if (is(UT == Json)) m_range.writeJsonString(value); 2048 else static if (is(UT == JSONValue)) m_range.writeJsonString(Json(value)); 2049 else static if (isJsonSerializable!UT) { 2050 static if (!__traits(compiles, () @safe { return value.toJson(); } ())) 2051 pragma(msg, "Non-@safe toJson/fromJson methods are deprecated - annotate "~UT.stringof~".toJson() with @safe."); 2052 m_range.writeJsonString!(R, pretty)(() @trusted { return value.toJson(); } (), m_level); 2053 } else static assert(false, "Unsupported type: " ~ UT.stringof); 2054 } 2055 2056 void writeStringSinkValue(Traits, T)(scope auto ref T value) 2057 { 2058 void sink(scope const(char)[] str) { 2059 m_range.jsonEscape(str); 2060 } 2061 2062 final class R { 2063 void put(char ch) { put(() @trusted { return (&ch)[0 .. 1]; } ()); } 2064 void put(scope const(char)[] str) { m_range.jsonEscape(str); } 2065 } 2066 2067 m_range.put('"'); 2068 static if (__traits(compiles, value.toString((scope s) => sink(s)))) { 2069 value.toString((scope s) => sink(s)); 2070 } else { 2071 scope r = new R; 2072 value.toString(r); 2073 } 2074 m_range.put('"'); 2075 } 2076 2077 private void startComposite() 2078 { 2079 static if (pretty) m_level++; 2080 m_firstInComposite = true; 2081 } 2082 2083 private void startCompositeEntry() 2084 { 2085 if (!m_firstInComposite) { 2086 m_range.put(','); 2087 } else { 2088 m_firstInComposite = false; 2089 } 2090 static if (pretty) indent(); 2091 } 2092 2093 private void endComposite() 2094 { 2095 static if (pretty) { 2096 m_level--; 2097 if (!m_firstInComposite) indent(); 2098 } 2099 m_firstInComposite = false; 2100 } 2101 2102 private void indent() 2103 { 2104 m_range.put('\n'); 2105 foreach (i; 0 .. m_level) m_range.put('\t'); 2106 } 2107 } 2108 2109 // 2110 // deserialization 2111 // 2112 static if (isInputRange!(R)) { 2113 private { 2114 int m_line = 0; 2115 } 2116 2117 void readDictionary(Traits)(scope void delegate(string) @safe entry_callback) 2118 { 2119 m_range.skipWhitespace(&m_line); 2120 enforceJson(!m_range.empty && m_range.front == '{', "Expecting object."); 2121 m_range.popFront(); 2122 bool first = true; 2123 while(true) { 2124 m_range.skipWhitespace(&m_line); 2125 enforceJson(!m_range.empty, "Missing '}'."); 2126 if (m_range.front == '}') { 2127 m_range.popFront(); 2128 break; 2129 } else if (!first) { 2130 enforceJson(m_range.front == ',', "Expecting ',' or '}', not '"~m_range.front.to!string~"'."); 2131 m_range.popFront(); 2132 m_range.skipWhitespace(&m_line); 2133 } else first = false; 2134 2135 auto name = m_range.skipJsonString(&m_line); 2136 2137 m_range.skipWhitespace(&m_line); 2138 enforceJson(!m_range.empty && m_range.front == ':', "Expecting ':', not '"~m_range.front.to!string~"'."); 2139 m_range.popFront(); 2140 2141 entry_callback(name); 2142 } 2143 } 2144 2145 void beginReadDictionaryEntry(Traits)(string name) {} 2146 void endReadDictionaryEntry(Traits)(string name) {} 2147 2148 void readArray(Traits)(scope void delegate(size_t) @safe size_callback, scope void delegate() @safe entry_callback) 2149 { 2150 m_range.skipWhitespace(&m_line); 2151 enforceJson(!m_range.empty && m_range.front == '[', "Expecting array."); 2152 m_range.popFront(); 2153 bool first = true; 2154 while(true) { 2155 m_range.skipWhitespace(&m_line); 2156 enforceJson(!m_range.empty, "Missing ']'."); 2157 if (m_range.front == ']') { 2158 m_range.popFront(); 2159 break; 2160 } else if (!first) { 2161 enforceJson(m_range.front == ',', "Expecting ',' or ']'."); 2162 m_range.popFront(); 2163 } else first = false; 2164 2165 entry_callback(); 2166 } 2167 } 2168 2169 void beginReadArrayEntry(Traits)(size_t index) {} 2170 void endReadArrayEntry(Traits)(size_t index) {} 2171 2172 T readValue(Traits, T)() 2173 { 2174 m_range.skipWhitespace(&m_line); 2175 static if (is(T == typeof(null))) { enforceJson(m_range.take(4).equal("null"), "Expecting 'null'."); return null; } 2176 else static if (is(T == bool)) { 2177 bool ret = m_range.front == 't'; 2178 string expected = ret ? "true" : "false"; 2179 foreach (ch; expected) { 2180 enforceJson(m_range.front == ch, "Expecting 'true' or 'false'."); 2181 m_range.popFront(); 2182 } 2183 return ret; 2184 } else static if (is(T : long)) { 2185 bool is_float; 2186 bool is_long_overflow; 2187 auto num = m_range.skipNumber(is_float, is_long_overflow); 2188 enforceJson(!is_float, "Expecting integer number."); 2189 enforceJson(!is_long_overflow, num.to!string~" is too big for long."); 2190 return to!T(num); 2191 } else static if (is(T : BigInt)) { 2192 bool is_float; 2193 bool is_long_overflow; 2194 auto num = m_range.skipNumber(is_float, is_long_overflow); 2195 enforceJson(!is_float, "Expecting integer number."); 2196 return BigInt(num); 2197 } else static if (is(T : real)) { 2198 bool is_float; 2199 bool is_long_overflow; 2200 auto num = m_range.skipNumber(is_float, is_long_overflow); 2201 return to!T(num); 2202 } 2203 else static if (is(T == string) || is(T == const(char)[])) { 2204 if (!m_range.empty && m_range.front == '[') { 2205 return () @trusted { // appender 2206 auto ret = appender!string(); 2207 readArray!Traits((sz) {}, () @trusted { 2208 ret.put(m_range.skipJsonString(&m_line)); 2209 }); 2210 return ret.data; 2211 } (); 2212 } else return m_range.skipJsonString(&m_line); 2213 } 2214 else static if (isSomeString!T) return readValue!(Traits, string).to!T; 2215 else static if (is(T == UUID)) return UUID(readValue!(Traits, string)()); 2216 else static if (is(T == Json)) return m_range.parseJson(&m_line); 2217 else static if (is(T == JSONValue)) return cast(JSONValue)m_range.parseJson(&m_line); 2218 else static if (isJsonSerializable!T) { 2219 static if (!__traits(compiles, () @safe { return T.fromJson(Json.init); } ())) 2220 pragma(msg, "Non-@safe toJson/fromJson methods are deprecated - annotate "~T.stringof~".fromJson() with @safe."); 2221 return () @trusted { return T.fromJson(m_range.parseJson(&m_line)); } (); 2222 } else static assert(false, "Unsupported type: " ~ T.stringof); 2223 } 2224 2225 bool tryReadNull(Traits)() 2226 { 2227 m_range.skipWhitespace(&m_line); 2228 if (m_range.front != 'n') return false; 2229 foreach (ch; "null") { 2230 enforceJson(m_range.front == ch, "Expecting 'null'."); 2231 m_range.popFront(); 2232 } 2233 assert(m_range.empty || m_range.front != 'l'); 2234 return true; 2235 } 2236 2237 void skipValue() @safe 2238 { 2239 m_range.skipWhitespace(&m_line); 2240 switch(m_range.front) { 2241 case '[': 2242 m_range.popFront(); 2243 bool first = true; 2244 while(true) { 2245 m_range.skipWhitespace(&m_line); 2246 enforceJson(!m_range.empty, "Missing ']'."); 2247 if (m_range.front == ']') { 2248 m_range.popFront(); 2249 break; 2250 } else if (!first) { 2251 enforceJson(m_range.front == ',', "Expecting ',' or ']'."); 2252 m_range.popFront(); 2253 } else first = false; 2254 skipValue(); 2255 } 2256 break; 2257 case '{': 2258 m_range.popFront(); 2259 bool first = true; 2260 while(true) { 2261 m_range.skipWhitespace(&m_line); 2262 enforceJson(!m_range.empty, "Missing '}'."); 2263 if (m_range.front == '}') { 2264 m_range.popFront(); 2265 break; 2266 } else if (!first) { 2267 enforceJson(m_range.front == ',', "Expecting ',' or '}', not '"~m_range.front.to!string~"'."); 2268 m_range.popFront(); 2269 m_range.skipWhitespace(&m_line); 2270 } else first = false; 2271 2272 m_range.skipJsonString(&m_line); 2273 2274 m_range.skipWhitespace(&m_line); 2275 enforceJson(!m_range.empty && m_range.front == ':', "Expecting ':', not '"~m_range.front.to!string~"'."); 2276 m_range.popFront(); 2277 2278 skipValue(); 2279 } 2280 break; 2281 case '"': 2282 m_range.skipJsonString(&m_line); 2283 break; 2284 case '-': 2285 case '0': .. case '9': 2286 bool dummy; // ignore 2287 m_range.skipNumber(dummy, dummy); 2288 break; 2289 case 't': 2290 foreach (ch; "true") { 2291 enforceJson(m_range.front == ch, "Expecting 'true'."); 2292 m_range.popFront(); 2293 } 2294 break; 2295 case 'f': 2296 foreach (ch; "false") { 2297 enforceJson(m_range.front == ch, "Expecting 'false'."); 2298 m_range.popFront(); 2299 } 2300 break; 2301 case 'n': 2302 foreach (ch; "null") { 2303 enforceJson(m_range.front == ch, "Expecting 'null'."); 2304 m_range.popFront(); 2305 } 2306 break; 2307 default: 2308 throw new JSONException("Expected start of object, array, string, number, boolean or null value, got"~m_range.front.to!string); 2309 } 2310 m_range.skipWhitespace(&m_line); 2311 } 2312 } 2313 } 2314 2315 unittest { 2316 static assert(doesSerializerSupportStringSink!(JsonStringSerializer!(Appender!string))); 2317 2318 auto app = appender!string; 2319 auto ser = JsonStringSerializer!(Appender!string)(app); 2320 static struct T1 { void toString(scope void delegate(scope const(char)[])) {} } 2321 static struct T2 { void toString(R)(scope ref R dst) { dst.put('f'); dst.put("foo"); } } 2322 2323 ser.writeStringSinkValue!void(T1.init); 2324 ser.writeStringSinkValue!void(T2.init); 2325 } 2326 2327 /// Cloning JSON arrays 2328 unittest 2329 { 2330 Json value = Json([ Json([ Json.emptyArray ]), Json.emptyArray ]).clone; 2331 2332 assert(value.length == 2); 2333 assert(value[0].length == 1); 2334 assert(value[0][0].length == 0); 2335 } 2336 2337 unittest 2338 { 2339 assert(serializeToJsonString(double.nan) == "null"); 2340 assert(serializeToJsonString(Json()) == "null"); 2341 assert(serializeToJsonString(Json(["bar":Json("baz"),"foo":Json()])) == `{"bar":"baz"}`); 2342 2343 struct Foo{Json bar = Json();} 2344 Foo f; 2345 assert(serializeToJsonString(f) == `{"bar":null}`); 2346 } 2347 2348 /** 2349 Writes the given JSON object as a JSON string into the destination range. 2350 2351 This function will convert the given JSON value to a string without adding 2352 any white space between tokens (no newlines, no indentation and no padding). 2353 The output size is thus minimized, at the cost of bad human readability. 2354 2355 Params: 2356 dst = References the string output range to which the result is written. 2357 json = Specifies the JSON value that is to be stringified. 2358 level = Specifies the base amount of indentation for the output. Indentation is always 2359 done using tab characters. 2360 2361 See_Also: Json.toString, writePrettyJsonString 2362 */ 2363 void writeJsonString(R, bool pretty = false)(ref R dst, in Json json, size_t level = 0) 2364 @safe // if( isOutputRange!R && is(ElementEncodingType!R == char) ) 2365 { 2366 final switch( json.type ){ 2367 case Json.Type.undefined: dst.put("null"); break; 2368 case Json.Type.null_: dst.put("null"); break; 2369 case Json.Type.bool_: dst.put(json.get!bool ? "true" : "false"); break; 2370 case Json.Type.int_: formattedWriteFixed!32(dst, "%d", json.get!long); break; 2371 case Json.Type.bigInt: 2372 () @trusted { 2373 static if (__VERSION__ < 2093) 2374 json.get!BigInt.toString((scope s) { dst.put(s); }, "%d"); 2375 else json.get!BigInt.toString(dst, "%d"); 2376 } (); 2377 break; 2378 case Json.Type.float_: 2379 auto d = json.get!double; 2380 if (d != d) 2381 dst.put("null"); // JSON has no NaN value so set null 2382 else 2383 formattedWriteFixed!32(dst, "%.16g", json.get!double); 2384 break; 2385 case Json.Type..string: 2386 dst.put('\"'); 2387 jsonEscape(dst, json.get!string); 2388 dst.put('\"'); 2389 break; 2390 case Json.Type.array: 2391 dst.put('['); 2392 bool first = true; 2393 foreach (ref const Json e; json.byValue) { 2394 if( !first ) dst.put(","); 2395 first = false; 2396 static if (pretty) { 2397 dst.put('\n'); 2398 foreach (tab; 0 .. level+1) dst.put('\t'); 2399 } 2400 if (e.type == Json.Type.undefined) dst.put("null"); 2401 else writeJsonString!(R, pretty)(dst, e, level+1); 2402 } 2403 static if (pretty) { 2404 if (json.length > 0) { 2405 dst.put('\n'); 2406 foreach (tab; 0 .. level) dst.put('\t'); 2407 } 2408 } 2409 dst.put(']'); 2410 break; 2411 case Json.Type.object: 2412 dst.put('{'); 2413 bool first = true; 2414 foreach (string k, ref const Json e; json.byKeyValue) { 2415 if( e.type == Json.Type.undefined ) continue; 2416 if( !first ) dst.put(','); 2417 first = false; 2418 static if (pretty) { 2419 dst.put('\n'); 2420 foreach (tab; 0 .. level+1) dst.put('\t'); 2421 } 2422 dst.put('\"'); 2423 jsonEscape(dst, k); 2424 dst.put(pretty ? `": ` : `":`); 2425 writeJsonString!(R, pretty)(dst, e, level+1); 2426 } 2427 static if (pretty) { 2428 if (json.length > 0) { 2429 dst.put('\n'); 2430 foreach (tab; 0 .. level) dst.put('\t'); 2431 } 2432 } 2433 dst.put('}'); 2434 break; 2435 } 2436 } 2437 2438 unittest { 2439 auto a = Json.emptyObject; 2440 a["a"] = Json.emptyArray; 2441 a["b"] = Json.emptyArray; 2442 a["b"] ~= Json(1); 2443 a["b"] ~= Json.emptyObject; 2444 2445 assert(a.toString() == `{"a":[],"b":[1,{}]}` || a.toString() == `{"b":[1,{}],"a":[]}`); 2446 assert(a.toPrettyString() == 2447 `{ 2448 "a": [], 2449 "b": [ 2450 1, 2451 {} 2452 ] 2453 }` 2454 || a.toPrettyString() == `{ 2455 "b": [ 2456 1, 2457 {} 2458 ], 2459 "a": [] 2460 }`); 2461 } 2462 2463 unittest { // #735 2464 auto a = Json.emptyArray; 2465 a ~= "a"; 2466 a ~= Json(); 2467 a ~= "b"; 2468 a ~= null; 2469 a ~= "c"; 2470 assert(a.toString() == `["a",null,"b",null,"c"]`); 2471 } 2472 2473 unittest { 2474 auto a = Json.emptyArray; 2475 a ~= Json(1); 2476 a ~= Json(2); 2477 a ~= Json(3); 2478 a ~= Json(4); 2479 a ~= Json(5); 2480 2481 auto b = Json(a[0..a.length]); 2482 assert(a == b); 2483 2484 auto c = Json(a[0..$]); 2485 assert(a == c); 2486 assert(b == c); 2487 2488 auto d = [Json(1),Json(2),Json(3)]; 2489 assert(d == a[0..a.length-2]); 2490 assert(d == a[0..$-2]); 2491 } 2492 2493 unittest { 2494 auto j = Json(double.init); 2495 2496 assert(j.toString == "null"); // A double nan should serialize to null 2497 j = 17.04f; 2498 assert(j.toString == "17.04"); // A proper double should serialize correctly 2499 2500 double d; 2501 deserializeJson(d, Json.undefined); // Json.undefined should deserialize to nan 2502 assert(d != d); 2503 deserializeJson(d, Json(null)); // Json.undefined should deserialize to nan 2504 assert(d != d); 2505 } 2506 /** 2507 Writes the given JSON object as a prettified JSON string into the destination range. 2508 2509 The output will contain newlines and indents to make the output human readable. 2510 2511 Params: 2512 dst = References the string output range to which the result is written. 2513 json = Specifies the JSON value that is to be stringified. 2514 level = Specifies the base amount of indentation for the output. Indentation is always 2515 done using tab characters. 2516 2517 See_Also: Json.toPrettyString, writeJsonString 2518 */ 2519 void writePrettyJsonString(R)(ref R dst, in Json json, int level = 0) 2520 // if( isOutputRange!R && is(ElementEncodingType!R == char) ) 2521 { 2522 writeJsonString!(R, true)(dst, json, level); 2523 } 2524 2525 2526 /** 2527 Helper function that escapes all Unicode characters in a JSON string. 2528 */ 2529 string convertJsonToASCII(string json) 2530 { 2531 auto ret = appender!string; 2532 jsonEscape!true(ret, json); 2533 return ret.data; 2534 } 2535 2536 2537 /// private 2538 private void jsonEscape(bool escape_unicode = false, R)(ref R dst, const(char)[] s) 2539 { 2540 size_t startPos = 0; 2541 2542 void putInterval(size_t curPos) 2543 { 2544 if (curPos > startPos) 2545 dst.put(s[startPos..curPos]); 2546 startPos = curPos + 1; 2547 } 2548 2549 for (size_t pos = 0; pos < s.length; pos++) { 2550 immutable(char) ch = s[pos]; 2551 2552 switch (ch) { 2553 default: 2554 static if (escape_unicode) { 2555 if (ch <= 0x20 || ch >= 0x80) 2556 { 2557 putInterval(pos); 2558 import std.utf : decode; 2559 int len; 2560 dchar codepoint = decode(s, pos); 2561 /* codepoint is in BMP */ 2562 if(codepoint < 0x10000) 2563 { 2564 dst.formattedWriteFixed!32("\\u%04X", codepoint); 2565 } 2566 /* not in BMP -> construct a UTF-16 surrogate pair */ 2567 else 2568 { 2569 int first, last; 2570 2571 codepoint -= 0x10000; 2572 first = 0xD800 | ((codepoint & 0xffc00) >> 10); 2573 last = 0xDC00 | (codepoint & 0x003ff); 2574 2575 dst.formattedWriteFixed!32("\\u%04X\\u%04X", first, last); 2576 } 2577 startPos = pos; 2578 pos -= 1; 2579 } 2580 } 2581 else 2582 { 2583 if (ch < 0x20) 2584 { 2585 putInterval(pos); 2586 dst.formattedWriteFixed!32("\\u%04X", ch); 2587 } 2588 } 2589 break; 2590 case '\\': putInterval(pos); dst.put("\\\\"); break; 2591 case '\r': putInterval(pos); dst.put("\\r"); break; 2592 case '\n': putInterval(pos); dst.put("\\n"); break; 2593 case '\t': putInterval(pos); dst.put("\\t"); break; 2594 case '\"': putInterval(pos); dst.put("\\\""); break; 2595 case '/': 2596 // this avoids the sequence "</" in the output, which is prone 2597 // to cross site scripting attacks when inserted into web pages 2598 if (pos > 0 && s[pos-1] == '<') 2599 { 2600 putInterval(pos); 2601 dst.put("\\/"); 2602 } 2603 break; 2604 } 2605 } 2606 // last interval 2607 putInterval(s.length); 2608 } 2609 2610 /// private 2611 private string jsonUnescape(R)(ref R range) 2612 { 2613 auto ret = appender!string(); 2614 while(!range.empty){ 2615 auto ch = range.front; 2616 switch( ch ){ 2617 case '"': return ret.data; 2618 case '\\': 2619 range.popFront(); 2620 enforceJson(!range.empty, "Unterminated string escape sequence."); 2621 switch(range.front){ 2622 default: enforceJson(false, "Invalid string escape sequence."); break; 2623 case '"': ret.put('\"'); range.popFront(); break; 2624 case '\\': ret.put('\\'); range.popFront(); break; 2625 case '/': ret.put('/'); range.popFront(); break; 2626 case 'b': ret.put('\b'); range.popFront(); break; 2627 case 'f': ret.put('\f'); range.popFront(); break; 2628 case 'n': ret.put('\n'); range.popFront(); break; 2629 case 'r': ret.put('\r'); range.popFront(); break; 2630 case 't': ret.put('\t'); range.popFront(); break; 2631 case 'u': 2632 2633 dchar decode_unicode_escape() { 2634 enforceJson(range.front == 'u'); 2635 range.popFront(); 2636 dchar uch = 0; 2637 foreach( i; 0 .. 4 ){ 2638 uch *= 16; 2639 enforceJson(!range.empty, "Unicode sequence must be '\\uXXXX'."); 2640 auto dc = range.front; 2641 range.popFront(); 2642 2643 if( dc >= '0' && dc <= '9' ) uch += dc - '0'; 2644 else if( dc >= 'a' && dc <= 'f' ) uch += dc - 'a' + 10; 2645 else if( dc >= 'A' && dc <= 'F' ) uch += dc - 'A' + 10; 2646 else enforceJson(false, "Unicode sequence must be '\\uXXXX'."); 2647 } 2648 return uch; 2649 } 2650 2651 auto uch = decode_unicode_escape(); 2652 2653 if(0xD800 <= uch && uch <= 0xDBFF) { 2654 /* surrogate pair */ 2655 range.popFront(); // backslash '\' 2656 auto uch2 = decode_unicode_escape(); 2657 enforceJson(0xDC00 <= uch2 && uch2 <= 0xDFFF, "invalid Unicode"); 2658 { 2659 /* valid second surrogate */ 2660 uch = 2661 ((uch - 0xD800) << 10) + 2662 (uch2 - 0xDC00) + 2663 0x10000; 2664 } 2665 } 2666 ret.put(uch); 2667 break; 2668 } 2669 break; 2670 default: 2671 ret.put(ch); 2672 range.popFront(); 2673 break; 2674 } 2675 } 2676 return ret.data; 2677 } 2678 2679 private auto skipNumber(R)(ref R s, out bool is_float, out bool is_long_overflow) @safe 2680 if (isNarrowString!R) 2681 { 2682 auto r = s.representation; 2683 version (assert) auto rEnd = (() @trusted => r.ptr + r.length - 1)(); 2684 auto res = skipNumber(r, is_float, is_long_overflow); 2685 version (assert) assert(rEnd == (() @trusted => r.ptr + r.length - 1)()); // check nothing taken off the end 2686 s = s[$ - r.length .. $]; 2687 return res.assumeUTF(); 2688 } 2689 2690 /// private 2691 private auto skipNumber(R)(ref R s, out bool is_float, out bool is_long_overflow) 2692 if (!isNarrowString!R && isForwardRange!R) 2693 { 2694 auto sOrig = s.save; 2695 size_t idx = 0; 2696 is_float = false; 2697 is_long_overflow = false; 2698 ulong int_part = 0; 2699 if (s.front == '-') { 2700 s.popFront(); ++idx; 2701 } 2702 if (s.front == '0') { 2703 s.popFront(); ++idx; 2704 } 2705 else { 2706 enforceJson(isDigit(s.front), "Digit expected at beginning of number."); 2707 int_part = s.front - '0'; 2708 s.popFront(); ++idx; 2709 while( !s.empty && isDigit(s.front) ) { 2710 if (!is_long_overflow) { 2711 auto dig = s.front - '0'; 2712 if ((long.max / 10) > int_part || ((long.max / 10) == int_part && (long.max % 10) >= dig)) { 2713 int_part *= 10; 2714 int_part += dig; 2715 } 2716 else { 2717 is_long_overflow = true; 2718 } 2719 } 2720 s.popFront(); ++idx; 2721 } 2722 } 2723 2724 if( !s.empty && s.front == '.' ) { 2725 s.popFront(); ++idx; 2726 is_float = true; 2727 while( !s.empty && isDigit(s.front) ) { 2728 s.popFront(); ++idx; 2729 } 2730 } 2731 2732 if( !s.empty && (s.front == 'e' || s.front == 'E') ) { 2733 s.popFront(); ++idx; 2734 is_float = true; 2735 if( !s.empty && (s.front == '+' || s.front == '-') ) { 2736 s.popFront(); ++idx; 2737 } 2738 enforceJson( !s.empty && isDigit(s.front), "Expected exponent." ~ sOrig.takeExactly(idx).to!string); 2739 s.popFront(); ++idx; 2740 while( !s.empty && isDigit(s.front) ) { 2741 s.popFront(); ++idx; 2742 } 2743 } 2744 2745 return sOrig.takeExactly(idx); 2746 } 2747 2748 unittest 2749 { 2750 import std.meta : AliasSeq; 2751 // test for string and for a simple range 2752 foreach (foo; AliasSeq!(to!string, map!"a")) { 2753 auto test_1 = foo("9223372036854775806"); // lower then long.max 2754 auto test_2 = foo("9223372036854775807"); // long.max 2755 auto test_3 = foo("9223372036854775808"); // greater then long.max 2756 bool is_float; 2757 bool is_long_overflow; 2758 test_1.skipNumber(is_float, is_long_overflow); 2759 assert(!is_long_overflow); 2760 test_2.skipNumber(is_float, is_long_overflow); 2761 assert(!is_long_overflow); 2762 test_3.skipNumber(is_float, is_long_overflow); 2763 assert(is_long_overflow); 2764 } 2765 } 2766 2767 /// private 2768 private string skipJsonString(R)(ref R s, int* line = null) 2769 { 2770 // TODO: count or disallow any newlines inside of the string 2771 enforceJson(!s.empty && s.front == '"', "Expected '\"' to start string."); 2772 s.popFront(); 2773 string ret = jsonUnescape(s); 2774 enforceJson(!s.empty && s.front == '"', "Expected '\"' to terminate string."); 2775 s.popFront(); 2776 return ret; 2777 } 2778 2779 /// private 2780 private void skipWhitespace(R)(ref R s, int* line = null) 2781 { 2782 while (!s.empty) { 2783 switch (s.front) { 2784 default: return; 2785 case ' ', '\t': s.popFront(); break; 2786 case '\n': 2787 s.popFront(); 2788 if (!s.empty && s.front == '\r') s.popFront(); 2789 if (line) (*line)++; 2790 break; 2791 case '\r': 2792 s.popFront(); 2793 if (!s.empty && s.front == '\n') s.popFront(); 2794 if (line) (*line)++; 2795 break; 2796 } 2797 } 2798 } 2799 2800 private bool isDigit(dchar ch) @safe nothrow pure { return ch >= '0' && ch <= '9'; } 2801 2802 private string underscoreStrip(string field_name) 2803 @safe nothrow pure { 2804 if( field_name.length < 1 || field_name[$-1] != '_' ) return field_name; 2805 else return field_name[0 .. $-1]; 2806 } 2807 2808 /// private 2809 package template isJsonSerializable(T) { enum isJsonSerializable = is(typeof(T.init.toJson()) : Json) && is(typeof(T.fromJson(Json())) : T); } 2810 2811 private void enforceJson(string file = __FILE__, size_t line = __LINE__)(bool cond, lazy string message = "JSON exception") 2812 { 2813 import std.exception : enforce; 2814 enforce!JSONException(cond, message, file, line); 2815 } 2816 2817 private void enforceJson(string file = __FILE__, size_t line = __LINE__)(bool cond, lazy string message, string err_file, int err_line) 2818 { 2819 import std.exception : enforce; 2820 enforce!JSONException(cond, format("%s(%s): Error: %s", err_file, err_line+1, message), file, line); 2821 } 2822 2823 private void enforceJson(string file = __FILE__, size_t line = __LINE__)(bool cond, lazy string message, string err_file, int* err_line) 2824 { 2825 enforceJson!(file, line)(cond, message, err_file, err_line ? *err_line : -1); 2826 } 2827 2828 private auto trustedRange(R)(R range) 2829 { 2830 static struct Rng { 2831 private R range; 2832 @property bool empty() @trusted { return range.empty; } 2833 @property auto front() @trusted { return range.front; } 2834 void popFront() @trusted { range.popFront(); } 2835 } 2836 return Rng(range); 2837 } 2838 2839 // test for vibe.utils.DictionaryList 2840 @safe unittest { 2841 import vibe.utils.dictionarylist; 2842 2843 static assert(isCustomSerializable!(DictionaryList!int)); 2844 2845 DictionaryList!(int, false) b; 2846 b.addField("a", 1); 2847 b.addField("A", 2); 2848 auto app = appender!string(); 2849 serializeToJson(app, b); 2850 assert(app.data == `[{"key":"a","value":1},{"key":"A","value":2}]`, app.data); 2851 2852 DictionaryList!(int, true, 2) c; 2853 c.addField("a", 1); 2854 c.addField("b", 2); 2855 c.addField("a", 3); 2856 c.remove("b"); 2857 auto appc = appender!string(); 2858 serializeToJson(appc, c); 2859 assert(appc.data == `[{"key":"a","value":1},{"key":"a","value":3}]`, appc.data); 2860 } 2861 2862 // make sure Json is usable for CTFE 2863 @safe unittest { 2864 static assert(is(typeof({ 2865 struct Test { 2866 Json object_ = Json.emptyObject; 2867 Json array = Json.emptyArray; 2868 } 2869 })), "CTFE for Json type failed."); 2870 2871 static Json test() { 2872 Json j; 2873 j = Json(42); 2874 j = Json([Json(true)]); 2875 j = Json(["foo": Json(null)]); 2876 j = Json("foo"); 2877 return j; 2878 } 2879 enum j = test(); 2880 static assert(j == Json("foo")); 2881 } 2882 2883 @safe unittest { // XSS prevention 2884 assert(Json("</script>some/path").toString() == `"<\/script>some/path"`); 2885 assert(serializeToJsonString("</script>some/path") == `"<\/script>some/path"`); 2886 } 2887 2888 @system unittest { // Recursive structures 2889 static struct Bar { Bar[] foos; int i; } 2890 auto b = deserializeJson!Bar(`{"i":1,"foos":[{"foos":[],"i":2}]}`); 2891 assert(b.i == 1); 2892 assert(b.foos.length == 1); 2893 assert(b.foos[0].i == 2); 2894 assert(b.foos[0].foos.length == 0); 2895 } 2896 2897 @safe unittest { // Json <-> std.json.JSONValue 2898 auto astr = `{ 2899 "null": null, 2900 "string": "Hello", 2901 "integer": 123456, 2902 "uinteger": 18446744073709551614, 2903 "float": 12.34, 2904 "object": { "hello": "world" }, 2905 "array": [1, 2, "string"], 2906 "true": true, 2907 "false": false 2908 }`; 2909 auto a = parseJsonString(astr); 2910 2911 // test JSONValue -> Json conversion 2912 assert(Json(cast(JSONValue)a) == a); 2913 2914 // test Json -> JSONValue conversion 2915 auto v = cast(JSONValue)a; 2916 assert(deserializeJson!JSONValue(serializeToJson(v)) == v); 2917 2918 // test JSON strint <-> JSONValue serialization 2919 assert(deserializeJson!JSONValue(astr) == v); 2920 assert(parseJsonString(serializeToJsonString(v)) == a); 2921 2922 // test using std.conv for the conversion 2923 import std.conv : to; 2924 assert(a.to!JSONValue.to!Json == a); 2925 assert(to!Json(to!JSONValue(a)) == a); 2926 } 2927 2928 @safe unittest { // issue #2150 - serialization of const/mutable strings + wide character strings 2929 assert(serializeToJson(cast(const(char)[])"foo") == Json("foo")); 2930 assert(serializeToJson("foo".dup) == Json("foo")); 2931 assert(deserializeJson!string(Json("foo")) == "foo"); 2932 assert(deserializeJson!string(Json([Json("f"), Json("o"), Json("o")])) == "foo"); 2933 assert(serializeToJsonString(cast(const(char)[])"foo") == "\"foo\""); 2934 assert(deserializeJson!string("\"foo\"") == "foo"); 2935 2936 assert(serializeToJson(cast(const(wchar)[])"foo"w) == Json("foo")); 2937 assert(serializeToJson("foo"w.dup) == Json("foo")); 2938 assert(deserializeJson!wstring(Json("foo")) == "foo"); 2939 assert(deserializeJson!wstring(Json([Json("f"), Json("o"), Json("o")])) == "foo"); 2940 assert(serializeToJsonString(cast(const(wchar)[])"foo"w) == "\"foo\""); 2941 assert(deserializeJson!wstring("\"foo\"") == "foo"); 2942 2943 assert(serializeToJson(cast(const(dchar)[])"foo"d) == Json("foo")); 2944 assert(serializeToJson("foo"d.dup) == Json("foo")); 2945 assert(deserializeJson!dstring(Json("foo")) == "foo"); 2946 assert(deserializeJson!dstring(Json([Json("f"), Json("o"), Json("o")])) == "foo"); 2947 assert(serializeToJsonString(cast(const(dchar)[])"foo"d) == "\"foo\""); 2948 assert(deserializeJson!dstring("\"foo\"") == "foo"); 2949 } 2950 2951 2952 unittest { // issue #1647 - JSON deserializeJson throws exception on unknown input fields 2953 struct S { 2954 string foo; 2955 } 2956 S expected = S("bar"); 2957 assert(deserializeJson!S(`{"foo":"bar","baz":"bam"}`) == expected); 2958 }