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