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