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