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