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; 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; 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(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(const(char)[]) @safe sink; 1150 void put(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(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(const(char)[]) sink; 1163 @trusted: 1164 void put(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 1171 /** 1172 Returns the JSON object as a "pretty" string. 1173 1174 --- 1175 auto json = Json(["foo": Json("bar")]); 1176 writeln(json.toPrettyString()); 1177 1178 // output: 1179 // { 1180 // "foo": "bar" 1181 // } 1182 --- 1183 1184 Params: 1185 level = Specifies the base amount of indentation for the output. Indentation is always 1186 done using tab characters. 1187 1188 See_Also: writePrettyJsonString, toString 1189 */ 1190 string toPrettyString(int level = 0) 1191 const @trusted { 1192 auto ret = appender!string(); 1193 writePrettyJsonString(ret, this, level); 1194 return ret.data; 1195 } 1196 1197 private void checkType(TYPES...)(string op = null) 1198 const { 1199 bool matched = false; 1200 foreach (T; TYPES) if (m_type == typeId!T) matched = true; 1201 if (matched) return; 1202 1203 string name; 1204 version (VibeJsonFieldNames) { 1205 if (m_name.length) name = m_name ~ " of type " ~ m_type.enumToString; 1206 else name = "JSON of type " ~ m_type.enumToString; 1207 } else name = "JSON of type " ~ m_type.enumToString; 1208 1209 string expected; 1210 static if (TYPES.length == 1) expected = typeId!(TYPES[0]).enumToString; 1211 else { 1212 foreach (T; TYPES) { 1213 if (expected.length > 0) expected ~= ", "; 1214 expected ~= typeId!T.enumToString; 1215 } 1216 } 1217 1218 if (!op.length) throw new JSONException(format("Got %s, expected %s.", name, expected)); 1219 else throw new JSONException(format("Got %s, expected %s for %s.", name, expected, op)); 1220 } 1221 1222 private void initBigInt() 1223 nothrow @trusted { 1224 // BigInt is a struct, and it has a special BigInt.init value, which differs from null. 1225 m_bigInt = BigInt.init; 1226 } 1227 1228 private void runDestructors() 1229 nothrow @trusted { 1230 if (m_type != Type.bigInt) 1231 { 1232 zeroFields; 1233 return; 1234 } 1235 1236 BigInt init_; 1237 // After swaping, init_ contains the real number from Json, and it 1238 // will be destroyed when this function is finished. 1239 // m_bigInt now contains static BigInt.init value and destruction may 1240 // be ommited for it. 1241 swap(init_, m_bigInt); 1242 } 1243 1244 private long bigIntToLong() inout @trusted 1245 { 1246 assert(m_type == Type.bigInt, format("Converting non-bigInt type with bitIntToLong!?: %s", (cast(Type)m_type).enumToString)); 1247 enforceJson(m_bigInt >= long.min && m_bigInt <= long.max, "Number out of range while converting BigInt("~format("%d", m_bigInt)~") to long."); 1248 return m_bigInt.toLong(); 1249 } 1250 1251 /*invariant() 1252 { 1253 assert(m_type >= Type.Undefined && m_type <= Type.Object); 1254 }*/ 1255 } 1256 1257 @safe unittest { // issue #1234 - @safe toString 1258 auto j = Json(true); 1259 j.toString((str) @safe {}, FormatSpec!char("s")); 1260 assert(j.toString() == "true"); 1261 } 1262 1263 1264 /******************************************************************************/ 1265 /* public functions */ 1266 /******************************************************************************/ 1267 1268 /** 1269 Parses the given range as a JSON string and returns the corresponding Json object. 1270 1271 The range is shrunk during parsing, leaving any remaining text that is not part of 1272 the JSON contents. 1273 1274 Throws a JSONException if any parsing error occured. 1275 */ 1276 Json parseJson(R)(ref R range, int* line = null, string filename = null) 1277 if (isForwardRange!R) 1278 { 1279 Json ret; 1280 enforceJson(!range.empty, "JSON string is empty.", filename, 0); 1281 1282 skipWhitespace(range, line); 1283 1284 enforceJson(!range.empty, "JSON string contains only whitespaces.", filename, 0); 1285 1286 version(JsonLineNumbers) { 1287 int curline = line ? *line : 0; 1288 } 1289 1290 bool minus = false; 1291 switch( range.front ){ 1292 case 'f': 1293 enforceJson(range.save.dropOne.startsWith("alse"), 1294 "Expected 'false', got '"~range.take(5).to!string~"'.", filename, line); 1295 range.popFrontN(5); 1296 ret = false; 1297 break; 1298 case 'n': 1299 enforceJson(range.save.dropOne.startsWith("ull"), 1300 "Expected 'null', got '"~range.take(4).to!string~"'.", filename, line); 1301 range.popFrontN(4); 1302 ret = null; 1303 break; 1304 case 't': 1305 enforceJson(range.save.dropOne.startsWith("rue"), 1306 "Expected 'true', got '"~range.take(4).to!string~"'.", filename, line); 1307 range.popFrontN(4); 1308 ret = true; 1309 break; 1310 1311 case '-': 1312 case '0': .. case '9': 1313 bool is_long_overflow; 1314 bool is_float; 1315 auto num = skipNumber(range, is_float, is_long_overflow); 1316 if( is_float ) { 1317 ret = to!double(num); 1318 } else if (is_long_overflow) { 1319 ret = () @trusted { return BigInt(num.to!string); } (); 1320 } else { 1321 ret = to!long(num); 1322 } 1323 break; 1324 case '\"': 1325 ret = skipJsonString(range); 1326 break; 1327 case '[': 1328 auto arr = appender!(Json[]); 1329 range.popFront(); 1330 while (true) { 1331 skipWhitespace(range, line); 1332 enforceJson(!range.empty, "Missing ']' before EOF.", filename, line); 1333 if(range.front == ']') break; 1334 arr ~= parseJson(range, line, filename); 1335 skipWhitespace(range, line); 1336 enforceJson(!range.empty, "Missing ']' before EOF.", filename, line); 1337 enforceJson(range.front == ',' || range.front == ']', 1338 format("Expected ']' or ',' - got '%s'.", range.front), filename, line); 1339 if( range.front == ']' ) break; 1340 else range.popFront(); 1341 } 1342 range.popFront(); 1343 ret = arr.data; 1344 break; 1345 case '{': 1346 Json[string] obj; 1347 range.popFront(); 1348 while (true) { 1349 skipWhitespace(range, line); 1350 enforceJson(!range.empty, "Missing '}' before EOF.", filename, line); 1351 if(range.front == '}') break; 1352 string key = skipJsonString(range); 1353 skipWhitespace(range, line); 1354 enforceJson(range.startsWith(":"), "Expected ':' for key '" ~ key ~ "'", filename, line); 1355 range.popFront(); 1356 skipWhitespace(range, line); 1357 Json itm = parseJson(range, line, filename); 1358 obj[key] = itm; 1359 skipWhitespace(range, line); 1360 enforceJson(!range.empty, "Missing '}' before EOF.", filename, line); 1361 enforceJson(range.front == ',' || range.front == '}', 1362 format("Expected '}' or ',' - got '%s'.", range.front), filename, line); 1363 if (range.front == '}') break; 1364 else range.popFront(); 1365 } 1366 range.popFront(); 1367 ret = obj; 1368 break; 1369 default: 1370 enforceJson(false, format("Expected valid JSON token, got '%s'.", range.take(12)), filename, line); 1371 assert(false); 1372 } 1373 1374 assert(ret.type != Json.Type.undefined); 1375 version(JsonLineNumbers) ret.line = curline; 1376 return ret; 1377 } 1378 1379 1380 unittest { // ensure parseJson works with a generic forward range 1381 static struct R { 1382 const(char)[] text; 1383 1384 @property char front() { return text[0]; } 1385 @property R save() { return this; } 1386 @property bool empty() const { return text.length == 0; } 1387 void popFront() { text = text[1 .. $]; } 1388 } 1389 1390 auto r = R(`{"i":42, "s": "foo"}`); 1391 auto j = parseJson(r); 1392 assert(j["i"] == 42); 1393 assert(j["s"] == "foo"); 1394 } 1395 1396 1397 /** 1398 Parses the given JSON string and returns the corresponding Json object. 1399 1400 Throws a JSONException if any parsing error occurs. 1401 */ 1402 Json parseJsonString(string str, string filename = null) 1403 @safe { 1404 auto strcopy = str; 1405 int line = 0; 1406 auto ret = parseJson(strcopy, () @trusted { return &line; } (), filename); 1407 enforceJson(strcopy.strip().length == 0, "Expected end of string after JSON value.", filename, line); 1408 return ret; 1409 } 1410 1411 @safe unittest { 1412 // These currently don't work at compile time 1413 assert(parseJsonString("17559991181826658461") == Json(BigInt(17559991181826658461UL))); 1414 assert(parseJsonString("99999999999999999999999999") == () @trusted { return Json(BigInt("99999999999999999999999999")); } ()); 1415 auto json = parseJsonString(`{"hey": "This is @à test éhééhhéhéé !%/??*&?\ud83d\udcec"}`); 1416 assert(json.toPrettyString() == parseJsonString(json.toPrettyString()).toPrettyString()); 1417 1418 bool test() { 1419 assert(parseJsonString("null") == Json(null)); 1420 assert(parseJsonString("true") == Json(true)); 1421 assert(parseJsonString("false") == Json(false)); 1422 assert(parseJsonString("1") == Json(1)); 1423 assert(parseJsonString("2.0") == Json(2.0)); 1424 assert(parseJsonString("\"test\"") == Json("test")); 1425 assert(parseJsonString("[1, 2, 3]") == Json([Json(1), Json(2), Json(3)])); 1426 assert(parseJsonString("{\"a\": 1}") == Json(["a": Json(1)])); 1427 assert(parseJsonString(`"\\\/\b\f\n\r\t\u1234"`).get!string == "\\/\b\f\n\r\t\u1234"); 1428 1429 return true; 1430 } 1431 1432 // Run at compile time and runtime 1433 assert(test()); 1434 static assert(test()); 1435 } 1436 1437 @safe nothrow unittest { 1438 bool test() { 1439 try parseJsonString(" \t\n "); 1440 catch (Exception e) assert(e.msg.endsWith("JSON string contains only whitespaces.")); 1441 try parseJsonString(`{"a": 1`); 1442 catch (Exception e) assert(e.msg.endsWith("Missing '}' before EOF.")); 1443 try parseJsonString(`{"a": 1 x`); 1444 catch (Exception e) assert(e.msg.endsWith("Expected '}' or ',' - got 'x'.")); 1445 try parseJsonString(`[1`); 1446 catch (Exception e) assert(e.msg.endsWith("Missing ']' before EOF.")); 1447 try parseJsonString(`[1 x`); 1448 catch (Exception e) assert(e.msg.endsWith("Expected ']' or ',' - got 'x'.")); 1449 1450 return true; 1451 } 1452 1453 // Run at compile time and runtime 1454 assert(test()); 1455 static assert(test()); 1456 } 1457 1458 /** 1459 Serializes the given value to JSON. 1460 1461 The following types of values are supported: 1462 1463 $(DL 1464 $(DT `Json`) $(DD Used as-is) 1465 $(DT `null`) $(DD Converted to `Json.Type.null_`) 1466 $(DT `bool`) $(DD Converted to `Json.Type.bool_`) 1467 $(DT `float`, `double`) $(DD Converted to `Json.Type.float_`) 1468 $(DT `short`, `ushort`, `int`, `uint`, `long`, `ulong`) $(DD Converted to `Json.Type.int_`) 1469 $(DT `BigInt`) $(DD Converted to `Json.Type.bigInt`) 1470 $(DT `string`) $(DD Converted to `Json.Type.string`) 1471 $(DT `T[]`) $(DD Converted to `Json.Type.array`) 1472 $(DT `T[string]`) $(DD Converted to `Json.Type.object`) 1473 $(DT `struct`) $(DD Converted to `Json.Type.object`) 1474 $(DT `class`) $(DD Converted to `Json.Type.object` or `Json.Type.null_`) 1475 ) 1476 1477 All entries of an array or an associative array, as well as all R/W properties and 1478 all public fields of a struct/class are recursively serialized using the same rules. 1479 1480 Fields ending with an underscore will have the last underscore stripped in the 1481 serialized output. This makes it possible to use fields with D keywords as their name 1482 by simply appending an underscore. 1483 1484 The following methods can be used to customize the serialization of structs/classes: 1485 1486 --- 1487 Json toJson() const; 1488 static T fromJson(Json src); 1489 1490 string toString() const; 1491 static T fromString(string src); 1492 --- 1493 1494 The methods will have to be defined in pairs. The first pair that is implemented by 1495 the type will be used for serialization (i.e. `toJson` overrides `toString`). 1496 1497 See_Also: `deserializeJson`, `vibe.data.serialization` 1498 */ 1499 Json serializeToJson(T)(auto ref T value) 1500 { 1501 return serialize!JsonSerializer(value); 1502 } 1503 /// ditto 1504 void serializeToJson(R, T)(R destination, auto ref T value) 1505 if (isOutputRange!(R, char) || isOutputRange!(R, ubyte)) 1506 { 1507 serialize!(JsonStringSerializer!R)(value, destination); 1508 } 1509 /// ditto 1510 string serializeToJsonString(T)(auto ref T value) 1511 { 1512 auto ret = appender!string; 1513 serializeToJson(ret, value); 1514 return ret.data; 1515 } 1516 1517 /// 1518 @safe unittest { 1519 struct Foo { 1520 int number; 1521 string str; 1522 } 1523 1524 Foo f; 1525 1526 f.number = 12; 1527 f.str = "hello"; 1528 1529 string json = serializeToJsonString(f); 1530 assert(json == `{"number":12,"str":"hello"}`); 1531 Json jsonval = serializeToJson(f); 1532 assert(jsonval.type == Json.Type.object); 1533 assert(jsonval["number"] == Json(12)); 1534 assert(jsonval["str"] == Json("hello")); 1535 } 1536 1537 1538 /** 1539 Serializes the given value to a pretty printed JSON string. 1540 1541 See_also: `serializeToJson`, `vibe.data.serialization` 1542 */ 1543 void serializeToPrettyJson(R, T)(R destination, auto ref T value) 1544 if (isOutputRange!(R, char) || isOutputRange!(R, ubyte)) 1545 { 1546 serialize!(JsonStringSerializer!(R, true))(value, destination); 1547 } 1548 /// ditto 1549 string serializeToPrettyJson(T)(auto ref T value) 1550 { 1551 auto ret = appender!string; 1552 serializeToPrettyJson(ret, value); 1553 return ret.data; 1554 } 1555 1556 /// 1557 @safe unittest { 1558 struct Foo { 1559 int number; 1560 string str; 1561 } 1562 1563 Foo f; 1564 f.number = 12; 1565 f.str = "hello"; 1566 1567 string json = serializeToPrettyJson(f); 1568 assert(json == 1569 `{ 1570 "number": 12, 1571 "str": "hello" 1572 }`); 1573 } 1574 1575 1576 /** 1577 Deserializes a JSON value into the destination variable. 1578 1579 The same types as for `serializeToJson()` are supported and handled inversely. 1580 1581 See_Also: `serializeToJson`, `serializeToJsonString`, `vibe.data.serialization` 1582 */ 1583 void deserializeJson(T)(ref T dst, Json src) 1584 { 1585 dst = deserializeJson!T(src); 1586 } 1587 /// ditto 1588 T deserializeJson(T)(Json src) 1589 { 1590 return deserialize!(JsonSerializer, T)(src); 1591 } 1592 /// ditto 1593 T deserializeJson(T, R)(R input) 1594 if (!is(R == Json) && isForwardRange!R) 1595 { 1596 return deserialize!(JsonStringSerializer!R, T)(input); 1597 } 1598 1599 /// 1600 @safe unittest { 1601 struct Foo { 1602 int number; 1603 string str; 1604 } 1605 Foo f = deserializeJson!Foo(`{"number": 12, "str": "hello"}`); 1606 assert(f.number == 12); 1607 assert(f.str == "hello"); 1608 } 1609 1610 @safe unittest { 1611 import std.stdio; 1612 enum Foo : string { k = "test" } 1613 enum Boo : int { l = 5 } 1614 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; } 1615 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}; 1616 S u; 1617 deserializeJson(u, serializeToJson(t)); 1618 assert(t.a == u.a); 1619 assert(t.b == u.b); 1620 assert(t.c == u.c); 1621 assert(t.d == u.d); 1622 assert(t.e == u.e); 1623 assert(t.f == u.f); 1624 assert(t.g == u.g); 1625 assert(t.h == u.h); 1626 assert(t.i == u.i); 1627 assert(t.j == u.j); 1628 assert(t.k == u.k); 1629 assert(t.l == u.l); 1630 } 1631 1632 @safe unittest 1633 { 1634 assert(uint.max == serializeToJson(uint.max).deserializeJson!uint); 1635 assert(ulong.max == serializeToJson(ulong.max).deserializeJson!ulong); 1636 } 1637 1638 @safe unittest { 1639 static struct A { int value; static A fromJson(Json val) @safe { return A(val.get!int); } Json toJson() const @safe { return Json(value); } } 1640 static struct C { int value; static C fromString(string val) @safe { return C(val.to!int); } string toString() const @safe { return value.to!string; } } 1641 static struct D { int value; } 1642 1643 assert(serializeToJson(const A(123)) == Json(123)); 1644 assert(serializeToJson(A(123)) == Json(123)); 1645 assert(serializeToJson(const C(123)) == Json("123")); 1646 assert(serializeToJson(C(123)) == Json("123")); 1647 assert(serializeToJson(const D(123)) == serializeToJson(["value": 123])); 1648 assert(serializeToJson(D(123)) == serializeToJson(["value": 123])); 1649 } 1650 1651 @safe unittest { 1652 auto d = Date(2001,1,1); 1653 deserializeJson(d, serializeToJson(Date.init)); 1654 assert(d == Date.init); 1655 deserializeJson(d, serializeToJson(Date(2001,1,1))); 1656 assert(d == Date(2001,1,1)); 1657 struct S { immutable(int)[] x; } 1658 S s; 1659 deserializeJson(s, serializeToJson(S([1,2,3]))); 1660 assert(s == S([1,2,3])); 1661 struct T { 1662 @optional S s; 1663 @optional int i; 1664 @optional float f_; // underscore strip feature 1665 @optional double d; 1666 @optional string str; 1667 } 1668 auto t = T(S([1,2,3])); 1669 deserializeJson(t, parseJsonString(`{ "s" : null, "i" : null, "f" : null, "d" : null, "str" : null }`)); 1670 assert(text(t) == text(T())); 1671 } 1672 1673 @safe unittest { 1674 static class C { 1675 @safe: 1676 int a; 1677 private int _b; 1678 @property int b() const { return _b; } 1679 @property void b(int v) { _b = v; } 1680 1681 @property int test() const { return 10; } 1682 1683 void test2() {} 1684 } 1685 C c = new C; 1686 c.a = 1; 1687 c.b = 2; 1688 1689 C d; 1690 deserializeJson(d, serializeToJson(c)); 1691 assert(c.a == d.a); 1692 assert(c.b == d.b); 1693 } 1694 1695 @safe unittest { 1696 static struct C { @safe: int value; static C fromString(string val) { return C(val.to!int); } string toString() const { return value.to!string; } } 1697 enum Color { Red, Green, Blue } 1698 { 1699 static class T { 1700 @safe: 1701 string[Color] enumIndexedMap; 1702 string[C] stringableIndexedMap; 1703 this() { 1704 enumIndexedMap = [ Color.Red : "magenta", Color.Blue : "deep blue" ]; 1705 stringableIndexedMap = [ C(42) : "forty-two" ]; 1706 } 1707 } 1708 1709 T original = new T; 1710 original.enumIndexedMap[Color.Green] = "olive"; 1711 T other; 1712 deserializeJson(other, serializeToJson(original)); 1713 assert(serializeToJson(other) == serializeToJson(original)); 1714 } 1715 { 1716 static struct S { 1717 string[Color] enumIndexedMap; 1718 string[C] stringableIndexedMap; 1719 } 1720 1721 S *original = new S; 1722 original.enumIndexedMap = [ Color.Red : "magenta", Color.Blue : "deep blue" ]; 1723 original.enumIndexedMap[Color.Green] = "olive"; 1724 original.stringableIndexedMap = [ C(42) : "forty-two" ]; 1725 S other; 1726 deserializeJson(other, serializeToJson(original)); 1727 assert(serializeToJson(other) == serializeToJson(original)); 1728 } 1729 } 1730 1731 @safe unittest { 1732 import std.typecons : Nullable; 1733 1734 struct S { Nullable!int a, b; } 1735 S s; 1736 s.a = 2; 1737 1738 auto j = serializeToJson(s); 1739 assert(j["a"].type == Json.Type.int_); 1740 assert(j["b"].type == Json.Type.null_); 1741 1742 auto t = deserializeJson!S(j); 1743 assert(!t.a.isNull() && t.a == 2); 1744 assert(t.b.isNull()); 1745 } 1746 1747 @safe unittest { // #840 1748 int[2][2] nestedArray = 1; 1749 assert(nestedArray.serializeToJson.deserializeJson!(typeof(nestedArray)) == nestedArray); 1750 } 1751 1752 @safe unittest { // #1109 1753 static class C { 1754 @safe: 1755 int mem; 1756 this(int m) { mem = m; } 1757 static C fromJson(Json j) { return new C(j.get!int-1); } 1758 Json toJson() const { return Json(mem+1); } 1759 } 1760 const c = new C(13); 1761 assert(serializeToJson(c) == Json(14)); 1762 assert(deserializeJson!C(Json(14)).mem == 13); 1763 } 1764 1765 @safe unittest { // const and mutable json 1766 Json j = Json(1); 1767 const k = Json(2); 1768 assert(serializeToJson(j) == Json(1)); 1769 assert(serializeToJson(k) == Json(2)); 1770 } 1771 1772 @safe unittest { // issue #1660 - deserialize AA whose key type is string-based enum 1773 enum Foo: string 1774 { 1775 Bar = "bar", 1776 Buzz = "buzz" 1777 } 1778 1779 struct S { 1780 int[Foo] f; 1781 } 1782 1783 const s = S([Foo.Bar: 2000]); 1784 assert(serializeToJson(s)["f"] == Json([Foo.Bar: Json(2000)])); 1785 1786 auto j = Json.emptyObject; 1787 j["f"] = [Foo.Bar: Json(2000)]; 1788 assert(deserializeJson!S(j).f == [Foo.Bar: 2000]); 1789 } 1790 1791 @safe unittest { 1792 struct V { 1793 UUID v; 1794 } 1795 1796 const u = UUID("318d7a61-e41b-494e-90d3-0a99f5531bfe"); 1797 const s = `{"v":"318d7a61-e41b-494e-90d3-0a99f5531bfe"}`; 1798 auto j = Json(["v": Json(u)]); 1799 1800 const v = V(u); 1801 1802 assert(serializeToJson(v) == j); 1803 1804 j = Json.emptyObject; 1805 j["v"] = u; 1806 assert(deserializeJson!V(j).v == u); 1807 1808 assert(serializeToJsonString(v) == s); 1809 assert(deserializeJson!V(s).v == u); 1810 } 1811 1812 /** 1813 Serializer for a plain Json representation. 1814 1815 See_Also: vibe.data.serialization.serialize, vibe.data.serialization.deserialize, serializeToJson, deserializeJson 1816 */ 1817 struct JsonSerializer { 1818 template isJsonBasicType(T) { enum isJsonBasicType = std.traits.isNumeric!T || isBoolean!T || isSomeString!T || is(T == typeof(null)) || is(Unqual!T == UUID) || isJsonSerializable!T; } 1819 1820 template isSupportedValueType(T) { enum isSupportedValueType = isJsonBasicType!T || is(Unqual!T == Json) || is(Unqual!T == JSONValue); } 1821 1822 private { 1823 Json m_current; 1824 Json[] m_compositeStack; 1825 } 1826 1827 this(Json data) @safe { m_current = data; } 1828 1829 @disable this(this); 1830 1831 // 1832 // serialization 1833 // 1834 Json getSerializedResult() @safe { return m_current; } 1835 void beginWriteDictionary(Traits)() { m_compositeStack ~= Json.emptyObject; } 1836 void endWriteDictionary(Traits)() { m_current = m_compositeStack[$-1]; m_compositeStack.length--; } 1837 void beginWriteDictionaryEntry(Traits)(string name) {} 1838 void endWriteDictionaryEntry(Traits)(string name) { m_compositeStack[$-1][name] = m_current; } 1839 1840 void beginWriteArray(Traits)(size_t) { m_compositeStack ~= Json.emptyArray; } 1841 void endWriteArray(Traits)() { m_current = m_compositeStack[$-1]; m_compositeStack.length--; } 1842 void beginWriteArrayEntry(Traits)(size_t) {} 1843 void endWriteArrayEntry(Traits)(size_t) { m_compositeStack[$-1].appendArrayElement(m_current); } 1844 1845 void writeValue(Traits, T)(auto ref T value) 1846 if (!is(Unqual!T == Json)) 1847 { 1848 alias UT = Unqual!T; 1849 static if (is(UT == JSONValue)) { 1850 m_current = Json(value); 1851 } else static if (isJsonSerializable!UT) { 1852 static if (!__traits(compiles, () @safe { return value.toJson(); } ())) 1853 pragma(msg, "Non-@safe toJson/fromJson methods are deprecated - annotate "~UT.stringof~".toJson() with @safe."); 1854 m_current = () @trusted { return value.toJson(); } (); 1855 } else static if (isSomeString!T && !is(UT == string)) { 1856 writeValue!Traits(value.to!string); 1857 } else m_current = Json(value); 1858 } 1859 1860 void writeValue(Traits, T)(auto ref T value) if (is(T == Json)) { m_current = value; } 1861 void writeValue(Traits, T)(auto ref T value) if (!is(T == Json) && is(T : const(Json))) { m_current = value.clone; } 1862 1863 // 1864 // deserialization 1865 // 1866 void readDictionary(Traits)(scope void delegate(string) @safe field_handler) 1867 { 1868 enforceJson(m_current.type == Json.Type.object, "Expected JSON object, got "~m_current.type.enumToString); 1869 auto old = m_current; 1870 foreach (string key, value; m_current.get!(Json[string])) { 1871 if (value.type == Json.Type.undefined) { 1872 continue; 1873 } 1874 1875 m_current = value; 1876 field_handler(key); 1877 } 1878 m_current = old; 1879 } 1880 1881 void beginReadDictionaryEntry(Traits)(string name) {} 1882 void endReadDictionaryEntry(Traits)(string name) {} 1883 1884 void readArray(Traits)(scope void delegate(size_t) @safe size_callback, scope void delegate() @safe entry_callback) 1885 { 1886 enforceJson(m_current.type == Json.Type.array, "Expected JSON array, got "~m_current.type.enumToString); 1887 auto old = m_current; 1888 size_callback(m_current.length); 1889 foreach (ent; old.get!(Json[])) { 1890 m_current = ent; 1891 entry_callback(); 1892 } 1893 m_current = old; 1894 } 1895 1896 void beginReadArrayEntry(Traits)(size_t index) {} 1897 void endReadArrayEntry(Traits)(size_t index) {} 1898 1899 T readValue(Traits, T)() 1900 @safe { 1901 static if (is(T == Json)) return m_current; 1902 else static if (is(T == JSONValue)) return cast(JSONValue)m_current; 1903 else static if (isJsonSerializable!T) { 1904 static if (!__traits(compiles, () @safe { return T.fromJson(m_current); } ())) 1905 pragma(msg, "Non-@safe toJson/fromJson methods are deprecated - annotate "~T.stringof~".fromJson() with @safe."); 1906 return () @trusted { return T.fromJson(m_current); } (); 1907 } else static if (is(T == float) || is(T == double)) { 1908 switch (m_current.type) { 1909 default: return cast(T)m_current.get!long; 1910 case Json.Type.null_: goto case; 1911 case Json.Type.undefined: return T.nan; 1912 case Json.Type.float_: return cast(T)m_current.get!double; 1913 case Json.Type.bigInt: return cast(T)m_current.bigIntToLong(); 1914 } 1915 } else static if (is(T == const(char)[])) { 1916 return readValue!(Traits, string); 1917 } else static if (isSomeString!T && !is(T == string)) { 1918 return readValue!(Traits, string).to!T; 1919 } else static if (is(T == string)) { 1920 if (m_current.type == Json.Type.array) { // legacy support for pre-#2150 serialization results 1921 return () @trusted { // appender 1922 auto r = appender!string; 1923 foreach (s; m_current.get!(Json[])) 1924 r.put(s.get!string()); 1925 return r.data; 1926 } (); 1927 } else return m_current.get!T(); 1928 } else return m_current.get!T(); 1929 } 1930 1931 bool tryReadNull(Traits)() { return m_current.type == Json.Type.null_; } 1932 } 1933 1934 unittest { 1935 struct T { 1936 @optional string a; 1937 } 1938 1939 auto obj = Json.emptyObject; 1940 obj["a"] = Json.undefined; 1941 assert(obj.deserializeJson!T.a == ""); 1942 } 1943 1944 unittest { 1945 class C { this(Json j) {foo = j;} Json foo; } 1946 const C c = new C(Json(42)); 1947 assert(serializeToJson(c)["foo"].get!int == 42); 1948 } 1949 1950 /** 1951 Serializer for a range based plain JSON string representation. 1952 1953 See_Also: vibe.data.serialization.serialize, vibe.data.serialization.deserialize, serializeToJson, deserializeJson 1954 */ 1955 struct JsonStringSerializer(R, bool pretty = false) 1956 if (isInputRange!R || isOutputRange!(R, char)) 1957 { 1958 private { 1959 R m_range; 1960 size_t m_level = 0; 1961 } 1962 1963 template isJsonBasicType(T) { enum isJsonBasicType = std.traits.isNumeric!T || isBoolean!T || isSomeString!T || is(T == typeof(null)) || is(Unqual!T == UUID) || isJsonSerializable!T; } 1964 1965 template isSupportedValueType(T) { enum isSupportedValueType = isJsonBasicType!(Unqual!T) || is(Unqual!T == Json) || is(Unqual!T == JSONValue); } 1966 1967 this(R range) 1968 { 1969 m_range = range; 1970 } 1971 1972 @disable this(this); 1973 1974 // 1975 // serialization 1976 // 1977 static if (isOutputRange!(R, char)) { 1978 private { 1979 bool m_firstInComposite; 1980 } 1981 1982 void getSerializedResult() {} 1983 1984 void beginWriteDictionary(Traits)() { startComposite(); m_range.put('{'); } 1985 void endWriteDictionary(Traits)() { endComposite(); m_range.put("}"); } 1986 void beginWriteDictionaryEntry(Traits)(string name) 1987 { 1988 startCompositeEntry(); 1989 m_range.put('"'); 1990 m_range.jsonEscape(name); 1991 static if (pretty) m_range.put(`": `); 1992 else m_range.put(`":`); 1993 } 1994 void endWriteDictionaryEntry(Traits)(string name) {} 1995 1996 void beginWriteArray(Traits)(size_t) { startComposite(); m_range.put('['); } 1997 void endWriteArray(Traits)() { endComposite(); m_range.put(']'); } 1998 void beginWriteArrayEntry(Traits)(size_t) { startCompositeEntry(); } 1999 void endWriteArrayEntry(Traits)(size_t) {} 2000 2001 void writeValue(Traits, T)(in T value) 2002 { 2003 alias UT = Unqual!T; 2004 static if (is(T == typeof(null))) m_range.put("null"); 2005 else static if (is(UT == bool)) m_range.put(value ? "true" : "false"); 2006 else static if (is(UT : long)) m_range.formattedWrite("%s", value); 2007 else static if (is(UT == BigInt)) () @trusted { m_range.formattedWrite("%d", value); } (); 2008 else static if (is(UT : real)) value == value ? m_range.formattedWrite("%.16g", value) : m_range.put("null"); 2009 else static if (is(UT : const(char)[])) { 2010 m_range.put('"'); 2011 m_range.jsonEscape(value); 2012 m_range.put('"'); 2013 } else static if (isSomeString!T) writeValue!Traits(value.to!string); // TODO: avoid memory allocation 2014 else static if (is(UT == UUID)) writeValue!Traits(value.toString()); 2015 else static if (is(UT == Json)) m_range.writeJsonString(value); 2016 else static if (is(UT == JSONValue)) m_range.writeJsonString(Json(value)); 2017 else static if (isJsonSerializable!UT) { 2018 static if (!__traits(compiles, () @safe { return value.toJson(); } ())) 2019 pragma(msg, "Non-@safe toJson/fromJson methods are deprecated - annotate "~UT.stringof~".toJson() with @safe."); 2020 m_range.writeJsonString!(R, pretty)(() @trusted { return value.toJson(); } (), m_level); 2021 } else static assert(false, "Unsupported type: " ~ UT.stringof); 2022 } 2023 2024 void writeStringSinkValue(Traits, T)(scope auto ref T value) 2025 { 2026 void sink(scope const(char)[] str) { 2027 m_range.jsonEscape(str); 2028 } 2029 2030 final class R { 2031 void put(char ch) { put(() @trusted { return (&ch)[0 .. 1]; } ()); } 2032 void put(scope const(char)[] str) { m_range.jsonEscape(str); } 2033 } 2034 2035 m_range.put('"'); 2036 static if (__traits(compiles, value.toString((scope s) => sink(s)))) { 2037 value.toString((scope s) => sink(s)); 2038 } else { 2039 scope r = new R; 2040 value.toString(r); 2041 } 2042 m_range.put('"'); 2043 } 2044 2045 private void startComposite() 2046 { 2047 static if (pretty) m_level++; 2048 m_firstInComposite = true; 2049 } 2050 2051 private void startCompositeEntry() 2052 { 2053 if (!m_firstInComposite) { 2054 m_range.put(','); 2055 } else { 2056 m_firstInComposite = false; 2057 } 2058 static if (pretty) indent(); 2059 } 2060 2061 private void endComposite() 2062 { 2063 static if (pretty) { 2064 m_level--; 2065 if (!m_firstInComposite) indent(); 2066 } 2067 m_firstInComposite = false; 2068 } 2069 2070 private void indent() 2071 { 2072 m_range.put('\n'); 2073 foreach (i; 0 .. m_level) m_range.put('\t'); 2074 } 2075 } 2076 2077 // 2078 // deserialization 2079 // 2080 static if (isInputRange!(R)) { 2081 private { 2082 int m_line = 0; 2083 } 2084 2085 void readDictionary(Traits)(scope void delegate(string) @safe entry_callback) 2086 { 2087 m_range.skipWhitespace(&m_line); 2088 enforceJson(!m_range.empty && m_range.front == '{', "Expecting object."); 2089 m_range.popFront(); 2090 bool first = true; 2091 while(true) { 2092 m_range.skipWhitespace(&m_line); 2093 enforceJson(!m_range.empty, "Missing '}'."); 2094 if (m_range.front == '}') { 2095 m_range.popFront(); 2096 break; 2097 } else if (!first) { 2098 enforceJson(m_range.front == ',', "Expecting ',' or '}', not '"~m_range.front.to!string~"'."); 2099 m_range.popFront(); 2100 m_range.skipWhitespace(&m_line); 2101 } else first = false; 2102 2103 auto name = m_range.skipJsonString(&m_line); 2104 2105 m_range.skipWhitespace(&m_line); 2106 enforceJson(!m_range.empty && m_range.front == ':', "Expecting ':', not '"~m_range.front.to!string~"'."); 2107 m_range.popFront(); 2108 2109 entry_callback(name); 2110 } 2111 } 2112 2113 void beginReadDictionaryEntry(Traits)(string name) {} 2114 void endReadDictionaryEntry(Traits)(string name) {} 2115 2116 void readArray(Traits)(scope void delegate(size_t) @safe size_callback, scope void delegate() @safe entry_callback) 2117 { 2118 m_range.skipWhitespace(&m_line); 2119 enforceJson(!m_range.empty && m_range.front == '[', "Expecting array."); 2120 m_range.popFront(); 2121 bool first = true; 2122 while(true) { 2123 m_range.skipWhitespace(&m_line); 2124 enforceJson(!m_range.empty, "Missing ']'."); 2125 if (m_range.front == ']') { 2126 m_range.popFront(); 2127 break; 2128 } else if (!first) { 2129 enforceJson(m_range.front == ',', "Expecting ',' or ']'."); 2130 m_range.popFront(); 2131 } else first = false; 2132 2133 entry_callback(); 2134 } 2135 } 2136 2137 void beginReadArrayEntry(Traits)(size_t index) {} 2138 void endReadArrayEntry(Traits)(size_t index) {} 2139 2140 T readValue(Traits, T)() 2141 { 2142 m_range.skipWhitespace(&m_line); 2143 static if (is(T == typeof(null))) { enforceJson(m_range.take(4).equal("null"), "Expecting 'null'."); return null; } 2144 else static if (is(T == bool)) { 2145 bool ret = m_range.front == 't'; 2146 string expected = ret ? "true" : "false"; 2147 foreach (ch; expected) { 2148 enforceJson(m_range.front == ch, "Expecting 'true' or 'false'."); 2149 m_range.popFront(); 2150 } 2151 return ret; 2152 } else static if (is(T : long)) { 2153 bool is_float; 2154 bool is_long_overflow; 2155 auto num = m_range.skipNumber(is_float, is_long_overflow); 2156 enforceJson(!is_float, "Expecting integer number."); 2157 enforceJson(!is_long_overflow, num.to!string~" is too big for long."); 2158 return to!T(num); 2159 } else static if (is(T : BigInt)) { 2160 bool is_float; 2161 bool is_long_overflow; 2162 auto num = m_range.skipNumber(is_float, is_long_overflow); 2163 enforceJson(!is_float, "Expecting integer number."); 2164 return BigInt(num); 2165 } else static if (is(T : real)) { 2166 bool is_float; 2167 bool is_long_overflow; 2168 auto num = m_range.skipNumber(is_float, is_long_overflow); 2169 return to!T(num); 2170 } 2171 else static if (is(T == string) || is(T == const(char)[])) { 2172 if (!m_range.empty && m_range.front == '[') { 2173 return () @trusted { // appender 2174 auto ret = appender!string(); 2175 readArray!Traits((sz) {}, () @trusted { 2176 ret.put(m_range.skipJsonString(&m_line)); 2177 }); 2178 return ret.data; 2179 } (); 2180 } else return m_range.skipJsonString(&m_line); 2181 } 2182 else static if (isSomeString!T) return readValue!(Traits, string).to!T; 2183 else static if (is(T == UUID)) return UUID(readValue!(Traits, string)()); 2184 else static if (is(T == Json)) return m_range.parseJson(&m_line); 2185 else static if (is(T == JSONValue)) return cast(JSONValue)m_range.parseJson(&m_line); 2186 else static if (isJsonSerializable!T) { 2187 static if (!__traits(compiles, () @safe { return T.fromJson(Json.init); } ())) 2188 pragma(msg, "Non-@safe toJson/fromJson methods are deprecated - annotate "~T.stringof~".fromJson() with @safe."); 2189 return () @trusted { return T.fromJson(m_range.parseJson(&m_line)); } (); 2190 } else static assert(false, "Unsupported type: " ~ T.stringof); 2191 } 2192 2193 bool tryReadNull(Traits)() 2194 { 2195 m_range.skipWhitespace(&m_line); 2196 if (m_range.front != 'n') return false; 2197 foreach (ch; "null") { 2198 enforceJson(m_range.front == ch, "Expecting 'null'."); 2199 m_range.popFront(); 2200 } 2201 assert(m_range.empty || m_range.front != 'l'); 2202 return true; 2203 } 2204 2205 void skipValue() @safe 2206 { 2207 m_range.skipWhitespace(&m_line); 2208 switch(m_range.front) { 2209 case '[': 2210 m_range.popFront(); 2211 bool first = true; 2212 while(true) { 2213 m_range.skipWhitespace(&m_line); 2214 enforceJson(!m_range.empty, "Missing ']'."); 2215 if (m_range.front == ']') { 2216 m_range.popFront(); 2217 break; 2218 } else if (!first) { 2219 enforceJson(m_range.front == ',', "Expecting ',' or ']'."); 2220 m_range.popFront(); 2221 } else first = false; 2222 skipValue(); 2223 } 2224 break; 2225 case '{': 2226 m_range.popFront(); 2227 bool first = true; 2228 while(true) { 2229 m_range.skipWhitespace(&m_line); 2230 enforceJson(!m_range.empty, "Missing '}'."); 2231 if (m_range.front == '}') { 2232 m_range.popFront(); 2233 break; 2234 } else if (!first) { 2235 enforceJson(m_range.front == ',', "Expecting ',' or '}', not '"~m_range.front.to!string~"'."); 2236 m_range.popFront(); 2237 m_range.skipWhitespace(&m_line); 2238 } else first = false; 2239 2240 m_range.skipJsonString(&m_line); 2241 2242 m_range.skipWhitespace(&m_line); 2243 enforceJson(!m_range.empty && m_range.front == ':', "Expecting ':', not '"~m_range.front.to!string~"'."); 2244 m_range.popFront(); 2245 2246 skipValue(); 2247 } 2248 break; 2249 case '"': 2250 m_range.skipJsonString(&m_line); 2251 break; 2252 case '-': 2253 case '0': .. case '9': 2254 bool dummy; // ignore 2255 m_range.skipNumber(dummy, dummy); 2256 break; 2257 case 't': 2258 foreach (ch; "true") { 2259 enforceJson(m_range.front == ch, "Expecting 'true'."); 2260 m_range.popFront(); 2261 } 2262 break; 2263 case 'f': 2264 foreach (ch; "false") { 2265 enforceJson(m_range.front == ch, "Expecting 'false'."); 2266 m_range.popFront(); 2267 } 2268 break; 2269 case 'n': 2270 foreach (ch; "null") { 2271 enforceJson(m_range.front == ch, "Expecting 'null'."); 2272 m_range.popFront(); 2273 } 2274 break; 2275 default: 2276 throw new JSONException("Expected start of object, array, string, number, boolean or null value, got"~m_range.front.to!string); 2277 } 2278 m_range.skipWhitespace(&m_line); 2279 } 2280 } 2281 } 2282 2283 unittest { 2284 static assert(doesSerializerSupportStringSink!(JsonStringSerializer!(Appender!string))); 2285 2286 auto app = appender!string; 2287 auto ser = JsonStringSerializer!(Appender!string)(app); 2288 static struct T1 { void toString(scope void delegate(scope const(char)[])) {} } 2289 static struct T2 { void toString(R)(scope ref R dst) { dst.put('f'); dst.put("foo"); } } 2290 2291 ser.writeStringSinkValue!void(T1.init); 2292 ser.writeStringSinkValue!void(T2.init); 2293 } 2294 2295 /// Cloning JSON arrays 2296 unittest 2297 { 2298 Json value = Json([ Json([ Json.emptyArray ]), Json.emptyArray ]).clone; 2299 2300 assert(value.length == 2); 2301 assert(value[0].length == 1); 2302 assert(value[0][0].length == 0); 2303 } 2304 2305 unittest 2306 { 2307 assert(serializeToJsonString(double.nan) == "null"); 2308 assert(serializeToJsonString(Json()) == "null"); 2309 assert(serializeToJsonString(Json(["bar":Json("baz"),"foo":Json()])) == `{"bar":"baz"}`); 2310 2311 struct Foo{Json bar = Json();} 2312 Foo f; 2313 assert(serializeToJsonString(f) == `{"bar":null}`); 2314 } 2315 2316 /** 2317 Writes the given JSON object as a JSON string into the destination range. 2318 2319 This function will convert the given JSON value to a string without adding 2320 any white space between tokens (no newlines, no indentation and no padding). 2321 The output size is thus minimized, at the cost of bad human readability. 2322 2323 Params: 2324 dst = References the string output range to which the result is written. 2325 json = Specifies the JSON value that is to be stringified. 2326 level = Specifies the base amount of indentation for the output. Indentation is always 2327 done using tab characters. 2328 2329 See_Also: Json.toString, writePrettyJsonString 2330 */ 2331 void writeJsonString(R, bool pretty = false)(ref R dst, in Json json, size_t level = 0) 2332 @safe // if( isOutputRange!R && is(ElementEncodingType!R == char) ) 2333 { 2334 final switch( json.type ){ 2335 case Json.Type.undefined: dst.put("null"); break; 2336 case Json.Type.null_: dst.put("null"); break; 2337 case Json.Type.bool_: dst.put(json.get!bool ? "true" : "false"); break; 2338 case Json.Type.int_: formattedWrite(dst, "%d", json.get!long); break; 2339 case Json.Type.bigInt: () @trusted { formattedWrite(dst, "%d", json.get!BigInt); } (); break; 2340 case Json.Type.float_: 2341 auto d = json.get!double; 2342 if (d != d) 2343 dst.put("null"); // JSON has no NaN value so set null 2344 else 2345 formattedWrite(dst, "%.16g", json.get!double); 2346 break; 2347 case Json.Type..string: 2348 dst.put('\"'); 2349 jsonEscape(dst, json.get!string); 2350 dst.put('\"'); 2351 break; 2352 case Json.Type.array: 2353 dst.put('['); 2354 bool first = true; 2355 foreach (ref const Json e; json.byValue) { 2356 if( !first ) dst.put(","); 2357 first = false; 2358 static if (pretty) { 2359 dst.put('\n'); 2360 foreach (tab; 0 .. level+1) dst.put('\t'); 2361 } 2362 if (e.type == Json.Type.undefined) dst.put("null"); 2363 else writeJsonString!(R, pretty)(dst, e, level+1); 2364 } 2365 static if (pretty) { 2366 if (json.length > 0) { 2367 dst.put('\n'); 2368 foreach (tab; 0 .. level) dst.put('\t'); 2369 } 2370 } 2371 dst.put(']'); 2372 break; 2373 case Json.Type.object: 2374 dst.put('{'); 2375 bool first = true; 2376 foreach (string k, ref const Json e; json.byKeyValue) { 2377 if( e.type == Json.Type.undefined ) continue; 2378 if( !first ) dst.put(','); 2379 first = false; 2380 static if (pretty) { 2381 dst.put('\n'); 2382 foreach (tab; 0 .. level+1) dst.put('\t'); 2383 } 2384 dst.put('\"'); 2385 jsonEscape(dst, k); 2386 dst.put(pretty ? `": ` : `":`); 2387 writeJsonString!(R, pretty)(dst, e, level+1); 2388 } 2389 static if (pretty) { 2390 if (json.length > 0) { 2391 dst.put('\n'); 2392 foreach (tab; 0 .. level) dst.put('\t'); 2393 } 2394 } 2395 dst.put('}'); 2396 break; 2397 } 2398 } 2399 2400 unittest { 2401 auto a = Json.emptyObject; 2402 a["a"] = Json.emptyArray; 2403 a["b"] = Json.emptyArray; 2404 a["b"] ~= Json(1); 2405 a["b"] ~= Json.emptyObject; 2406 2407 assert(a.toString() == `{"a":[],"b":[1,{}]}` || a.toString() == `{"b":[1,{}],"a":[]}`); 2408 assert(a.toPrettyString() == 2409 `{ 2410 "a": [], 2411 "b": [ 2412 1, 2413 {} 2414 ] 2415 }` 2416 || a.toPrettyString() == `{ 2417 "b": [ 2418 1, 2419 {} 2420 ], 2421 "a": [] 2422 }`); 2423 } 2424 2425 unittest { // #735 2426 auto a = Json.emptyArray; 2427 a ~= "a"; 2428 a ~= Json(); 2429 a ~= "b"; 2430 a ~= null; 2431 a ~= "c"; 2432 assert(a.toString() == `["a",null,"b",null,"c"]`); 2433 } 2434 2435 unittest { 2436 auto a = Json.emptyArray; 2437 a ~= Json(1); 2438 a ~= Json(2); 2439 a ~= Json(3); 2440 a ~= Json(4); 2441 a ~= Json(5); 2442 2443 auto b = Json(a[0..a.length]); 2444 assert(a == b); 2445 2446 auto c = Json(a[0..$]); 2447 assert(a == c); 2448 assert(b == c); 2449 2450 auto d = [Json(1),Json(2),Json(3)]; 2451 assert(d == a[0..a.length-2]); 2452 assert(d == a[0..$-2]); 2453 } 2454 2455 unittest { 2456 auto j = Json(double.init); 2457 2458 assert(j.toString == "null"); // A double nan should serialize to null 2459 j = 17.04f; 2460 assert(j.toString == "17.04"); // A proper double should serialize correctly 2461 2462 double d; 2463 deserializeJson(d, Json.undefined); // Json.undefined should deserialize to nan 2464 assert(d != d); 2465 deserializeJson(d, Json(null)); // Json.undefined should deserialize to nan 2466 assert(d != d); 2467 } 2468 /** 2469 Writes the given JSON object as a prettified JSON string into the destination range. 2470 2471 The output will contain newlines and indents to make the output human readable. 2472 2473 Params: 2474 dst = References the string output range to which the result is written. 2475 json = Specifies the JSON value that is to be stringified. 2476 level = Specifies the base amount of indentation for the output. Indentation is always 2477 done using tab characters. 2478 2479 See_Also: Json.toPrettyString, writeJsonString 2480 */ 2481 void writePrettyJsonString(R)(ref R dst, in Json json, int level = 0) 2482 // if( isOutputRange!R && is(ElementEncodingType!R == char) ) 2483 { 2484 writeJsonString!(R, true)(dst, json, level); 2485 } 2486 2487 2488 /** 2489 Helper function that escapes all Unicode characters in a JSON string. 2490 */ 2491 string convertJsonToASCII(string json) 2492 { 2493 auto ret = appender!string; 2494 jsonEscape!true(ret, json); 2495 return ret.data; 2496 } 2497 2498 2499 /// private 2500 private void jsonEscape(bool escape_unicode = false, R)(ref R dst, const(char)[] s) 2501 { 2502 size_t startPos = 0; 2503 2504 void putInterval(size_t curPos) 2505 { 2506 if (curPos > startPos) 2507 dst.put(s[startPos..curPos]); 2508 startPos = curPos + 1; 2509 } 2510 2511 for (size_t pos = 0; pos < s.length; pos++) { 2512 immutable(char) ch = s[pos]; 2513 2514 switch (ch) { 2515 default: 2516 static if (escape_unicode) { 2517 if (ch <= 0x20 || ch >= 0x80) 2518 { 2519 putInterval(pos); 2520 import std.utf : decode; 2521 int len; 2522 dchar codepoint = decode(s, pos); 2523 /* codepoint is in BMP */ 2524 if(codepoint < 0x10000) 2525 { 2526 dst.formattedWrite("\\u%04X", codepoint); 2527 } 2528 /* not in BMP -> construct a UTF-16 surrogate pair */ 2529 else 2530 { 2531 int first, last; 2532 2533 codepoint -= 0x10000; 2534 first = 0xD800 | ((codepoint & 0xffc00) >> 10); 2535 last = 0xDC00 | (codepoint & 0x003ff); 2536 2537 dst.formattedWrite("\\u%04X\\u%04X", first, last); 2538 } 2539 startPos = pos; 2540 pos -= 1; 2541 } 2542 } 2543 else 2544 { 2545 if (ch < 0x20) 2546 { 2547 putInterval(pos); 2548 dst.formattedWrite("\\u%04X", ch); 2549 } 2550 } 2551 break; 2552 case '\\': putInterval(pos); dst.put("\\\\"); break; 2553 case '\r': putInterval(pos); dst.put("\\r"); break; 2554 case '\n': putInterval(pos); dst.put("\\n"); break; 2555 case '\t': putInterval(pos); dst.put("\\t"); break; 2556 case '\"': putInterval(pos); dst.put("\\\""); break; 2557 case '/': 2558 // this avoids the sequence "</" in the output, which is prone 2559 // to cross site scripting attacks when inserted into web pages 2560 if (pos > 0 && s[pos-1] == '<') 2561 { 2562 putInterval(pos); 2563 dst.put("\\/"); 2564 } 2565 break; 2566 } 2567 } 2568 // last interval 2569 putInterval(s.length); 2570 } 2571 2572 /// private 2573 private string jsonUnescape(R)(ref R range) 2574 { 2575 auto ret = appender!string(); 2576 while(!range.empty){ 2577 auto ch = range.front; 2578 switch( ch ){ 2579 case '"': return ret.data; 2580 case '\\': 2581 range.popFront(); 2582 enforceJson(!range.empty, "Unterminated string escape sequence."); 2583 switch(range.front){ 2584 default: enforceJson(false, "Invalid string escape sequence."); break; 2585 case '"': ret.put('\"'); range.popFront(); break; 2586 case '\\': ret.put('\\'); range.popFront(); break; 2587 case '/': ret.put('/'); range.popFront(); break; 2588 case 'b': ret.put('\b'); range.popFront(); break; 2589 case 'f': ret.put('\f'); range.popFront(); break; 2590 case 'n': ret.put('\n'); range.popFront(); break; 2591 case 'r': ret.put('\r'); range.popFront(); break; 2592 case 't': ret.put('\t'); range.popFront(); break; 2593 case 'u': 2594 2595 dchar decode_unicode_escape() { 2596 enforceJson(range.front == 'u'); 2597 range.popFront(); 2598 dchar uch = 0; 2599 foreach( i; 0 .. 4 ){ 2600 uch *= 16; 2601 enforceJson(!range.empty, "Unicode sequence must be '\\uXXXX'."); 2602 auto dc = range.front; 2603 range.popFront(); 2604 2605 if( dc >= '0' && dc <= '9' ) uch += dc - '0'; 2606 else if( dc >= 'a' && dc <= 'f' ) uch += dc - 'a' + 10; 2607 else if( dc >= 'A' && dc <= 'F' ) uch += dc - 'A' + 10; 2608 else enforceJson(false, "Unicode sequence must be '\\uXXXX'."); 2609 } 2610 return uch; 2611 } 2612 2613 auto uch = decode_unicode_escape(); 2614 2615 if(0xD800 <= uch && uch <= 0xDBFF) { 2616 /* surrogate pair */ 2617 range.popFront(); // backslash '\' 2618 auto uch2 = decode_unicode_escape(); 2619 enforceJson(0xDC00 <= uch2 && uch2 <= 0xDFFF, "invalid Unicode"); 2620 { 2621 /* valid second surrogate */ 2622 uch = 2623 ((uch - 0xD800) << 10) + 2624 (uch2 - 0xDC00) + 2625 0x10000; 2626 } 2627 } 2628 ret.put(uch); 2629 break; 2630 } 2631 break; 2632 default: 2633 ret.put(ch); 2634 range.popFront(); 2635 break; 2636 } 2637 } 2638 return ret.data; 2639 } 2640 2641 private auto skipNumber(R)(ref R s, out bool is_float, out bool is_long_overflow) @safe 2642 if (isNarrowString!R) 2643 { 2644 auto r = s.representation; 2645 version (assert) auto rEnd = (() @trusted => r.ptr + r.length - 1)(); 2646 auto res = skipNumber(r, is_float, is_long_overflow); 2647 version (assert) assert(rEnd == (() @trusted => r.ptr + r.length - 1)()); // check nothing taken off the end 2648 s = s[$ - r.length .. $]; 2649 return res.assumeUTF(); 2650 } 2651 2652 /// private 2653 private auto skipNumber(R)(ref R s, out bool is_float, out bool is_long_overflow) 2654 if (!isNarrowString!R && isForwardRange!R) 2655 { 2656 auto sOrig = s.save; 2657 size_t idx = 0; 2658 is_float = false; 2659 is_long_overflow = false; 2660 ulong int_part = 0; 2661 if (s.front == '-') { 2662 s.popFront(); ++idx; 2663 } 2664 if (s.front == '0') { 2665 s.popFront(); ++idx; 2666 } 2667 else { 2668 enforceJson(isDigit(s.front), "Digit expected at beginning of number."); 2669 int_part = s.front - '0'; 2670 s.popFront(); ++idx; 2671 while( !s.empty && isDigit(s.front) ) { 2672 if (!is_long_overflow) { 2673 auto dig = s.front - '0'; 2674 if ((long.max / 10) > int_part || ((long.max / 10) == int_part && (long.max % 10) >= dig)) { 2675 int_part *= 10; 2676 int_part += dig; 2677 } 2678 else { 2679 is_long_overflow = true; 2680 } 2681 } 2682 s.popFront(); ++idx; 2683 } 2684 } 2685 2686 if( !s.empty && s.front == '.' ) { 2687 s.popFront(); ++idx; 2688 is_float = true; 2689 while( !s.empty && isDigit(s.front) ) { 2690 s.popFront(); ++idx; 2691 } 2692 } 2693 2694 if( !s.empty && (s.front == 'e' || s.front == 'E') ) { 2695 s.popFront(); ++idx; 2696 is_float = true; 2697 if( !s.empty && (s.front == '+' || s.front == '-') ) { 2698 s.popFront(); ++idx; 2699 } 2700 enforceJson( !s.empty && isDigit(s.front), "Expected exponent." ~ sOrig.takeExactly(idx).to!string); 2701 s.popFront(); ++idx; 2702 while( !s.empty && isDigit(s.front) ) { 2703 s.popFront(); ++idx; 2704 } 2705 } 2706 2707 return sOrig.takeExactly(idx); 2708 } 2709 2710 unittest 2711 { 2712 import std.meta : AliasSeq; 2713 // test for string and for a simple range 2714 foreach (foo; AliasSeq!(to!string, map!"a")) { 2715 auto test_1 = foo("9223372036854775806"); // lower then long.max 2716 auto test_2 = foo("9223372036854775807"); // long.max 2717 auto test_3 = foo("9223372036854775808"); // greater then long.max 2718 bool is_float; 2719 bool is_long_overflow; 2720 test_1.skipNumber(is_float, is_long_overflow); 2721 assert(!is_long_overflow); 2722 test_2.skipNumber(is_float, is_long_overflow); 2723 assert(!is_long_overflow); 2724 test_3.skipNumber(is_float, is_long_overflow); 2725 assert(is_long_overflow); 2726 } 2727 } 2728 2729 /// private 2730 private string skipJsonString(R)(ref R s, int* line = null) 2731 { 2732 // TODO: count or disallow any newlines inside of the string 2733 enforceJson(!s.empty && s.front == '"', "Expected '\"' to start string."); 2734 s.popFront(); 2735 string ret = jsonUnescape(s); 2736 enforceJson(!s.empty && s.front == '"', "Expected '\"' to terminate string."); 2737 s.popFront(); 2738 return ret; 2739 } 2740 2741 /// private 2742 private void skipWhitespace(R)(ref R s, int* line = null) 2743 { 2744 while (!s.empty) { 2745 switch (s.front) { 2746 default: return; 2747 case ' ', '\t': s.popFront(); break; 2748 case '\n': 2749 s.popFront(); 2750 if (!s.empty && s.front == '\r') s.popFront(); 2751 if (line) (*line)++; 2752 break; 2753 case '\r': 2754 s.popFront(); 2755 if (!s.empty && s.front == '\n') s.popFront(); 2756 if (line) (*line)++; 2757 break; 2758 } 2759 } 2760 } 2761 2762 private bool isDigit(dchar ch) @safe nothrow pure { return ch >= '0' && ch <= '9'; } 2763 2764 private string underscoreStrip(string field_name) 2765 @safe nothrow pure { 2766 if( field_name.length < 1 || field_name[$-1] != '_' ) return field_name; 2767 else return field_name[0 .. $-1]; 2768 } 2769 2770 /// private 2771 package template isJsonSerializable(T) { enum isJsonSerializable = is(typeof(T.init.toJson()) : Json) && is(typeof(T.fromJson(Json())) : T); } 2772 2773 private void enforceJson(string file = __FILE__, size_t line = __LINE__)(bool cond, lazy string message = "JSON exception") 2774 { 2775 import std.exception : enforce; 2776 enforce!JSONException(cond, message, file, line); 2777 } 2778 2779 private void enforceJson(string file = __FILE__, size_t line = __LINE__)(bool cond, lazy string message, string err_file, int err_line) 2780 { 2781 import std.exception : enforce; 2782 enforce!JSONException(cond, format("%s(%s): Error: %s", err_file, err_line+1, message), file, line); 2783 } 2784 2785 private void enforceJson(string file = __FILE__, size_t line = __LINE__)(bool cond, lazy string message, string err_file, int* err_line) 2786 { 2787 enforceJson!(file, line)(cond, message, err_file, err_line ? *err_line : -1); 2788 } 2789 2790 private auto trustedRange(R)(R range) 2791 { 2792 static struct Rng { 2793 private R range; 2794 @property bool empty() @trusted { return range.empty; } 2795 @property auto front() @trusted { return range.front; } 2796 void popFront() @trusted { range.popFront(); } 2797 } 2798 return Rng(range); 2799 } 2800 2801 // test for vibe.utils.DictionaryList 2802 @safe unittest { 2803 import vibe.utils.dictionarylist; 2804 2805 static assert(isCustomSerializable!(DictionaryList!int)); 2806 2807 DictionaryList!(int, false) b; 2808 b.addField("a", 1); 2809 b.addField("A", 2); 2810 auto app = appender!string(); 2811 serializeToJson(app, b); 2812 assert(app.data == `[{"key":"a","value":1},{"key":"A","value":2}]`, app.data); 2813 2814 DictionaryList!(int, true, 2) c; 2815 c.addField("a", 1); 2816 c.addField("b", 2); 2817 c.addField("a", 3); 2818 c.remove("b"); 2819 auto appc = appender!string(); 2820 serializeToJson(appc, c); 2821 assert(appc.data == `[{"key":"a","value":1},{"key":"a","value":3}]`, appc.data); 2822 } 2823 2824 // make sure Json is usable for CTFE 2825 @safe unittest { 2826 static assert(is(typeof({ 2827 struct Test { 2828 Json object_ = Json.emptyObject; 2829 Json array = Json.emptyArray; 2830 } 2831 })), "CTFE for Json type failed."); 2832 2833 static Json test() { 2834 Json j; 2835 j = Json(42); 2836 j = Json([Json(true)]); 2837 j = Json(["foo": Json(null)]); 2838 j = Json("foo"); 2839 return j; 2840 } 2841 enum j = test(); 2842 static assert(j == Json("foo")); 2843 } 2844 2845 @safe unittest { // XSS prevention 2846 assert(Json("</script>some/path").toString() == `"<\/script>some/path"`); 2847 assert(serializeToJsonString("</script>some/path") == `"<\/script>some/path"`); 2848 } 2849 2850 @system unittest { // Recursive structures 2851 static struct Bar { Bar[] foos; int i; } 2852 auto b = deserializeJson!Bar(`{"i":1,"foos":[{"foos":[],"i":2}]}`); 2853 assert(b.i == 1); 2854 assert(b.foos.length == 1); 2855 assert(b.foos[0].i == 2); 2856 assert(b.foos[0].foos.length == 0); 2857 } 2858 2859 @safe unittest { // Json <-> std.json.JSONValue 2860 auto astr = `{ 2861 "null": null, 2862 "string": "Hello", 2863 "integer": 123456, 2864 "uinteger": 18446744073709551614, 2865 "float": 12.34, 2866 "object": { "hello": "world" }, 2867 "array": [1, 2, "string"], 2868 "true": true, 2869 "false": false 2870 }`; 2871 auto a = parseJsonString(astr); 2872 2873 // test JSONValue -> Json conversion 2874 assert(Json(cast(JSONValue)a) == a); 2875 2876 // test Json -> JSONValue conversion 2877 auto v = cast(JSONValue)a; 2878 assert(deserializeJson!JSONValue(serializeToJson(v)) == v); 2879 2880 // test JSON strint <-> JSONValue serialization 2881 assert(deserializeJson!JSONValue(astr) == v); 2882 assert(parseJsonString(serializeToJsonString(v)) == a); 2883 2884 // test using std.conv for the conversion 2885 import std.conv : to; 2886 assert(a.to!JSONValue.to!Json == a); 2887 assert(to!Json(to!JSONValue(a)) == a); 2888 } 2889 2890 @safe unittest { // issue #2150 - serialization of const/mutable strings + wide character strings 2891 assert(serializeToJson(cast(const(char)[])"foo") == Json("foo")); 2892 assert(serializeToJson("foo".dup) == Json("foo")); 2893 assert(deserializeJson!string(Json("foo")) == "foo"); 2894 assert(deserializeJson!string(Json([Json("f"), Json("o"), Json("o")])) == "foo"); 2895 assert(serializeToJsonString(cast(const(char)[])"foo") == "\"foo\""); 2896 assert(deserializeJson!string("\"foo\"") == "foo"); 2897 2898 assert(serializeToJson(cast(const(wchar)[])"foo"w) == Json("foo")); 2899 assert(serializeToJson("foo"w.dup) == Json("foo")); 2900 assert(deserializeJson!wstring(Json("foo")) == "foo"); 2901 assert(deserializeJson!wstring(Json([Json("f"), Json("o"), Json("o")])) == "foo"); 2902 assert(serializeToJsonString(cast(const(wchar)[])"foo"w) == "\"foo\""); 2903 assert(deserializeJson!wstring("\"foo\"") == "foo"); 2904 2905 assert(serializeToJson(cast(const(dchar)[])"foo"d) == Json("foo")); 2906 assert(serializeToJson("foo"d.dup) == Json("foo")); 2907 assert(deserializeJson!dstring(Json("foo")) == "foo"); 2908 assert(deserializeJson!dstring(Json([Json("f"), Json("o"), Json("o")])) == "foo"); 2909 assert(serializeToJsonString(cast(const(dchar)[])"foo"d) == "\"foo\""); 2910 assert(deserializeJson!dstring("\"foo\"") == "foo"); 2911 } 2912 2913 2914 unittest { // issue #1647 - JSON deserializeJson throws exception on unknown input fields 2915 struct S { 2916 string foo; 2917 } 2918 S expected = S("bar"); 2919 assert(deserializeJson!S(`{"foo":"bar","baz":"bam"}`) == expected); 2920 }