1 /***************************************************************************************************
2  * 
3  * A fast JSON parser implementing RFC 7159.
4  * 
5  * The most prominent change compared to the initial revision is the allowance of all data types as
6  * root values, not just objects and arrays.
7  * 
8  * Usage_Hints:
9  *   $(UL
10  *     $(LI This parser only supports UTF-8 without BOM.)
11  *     $(LI When a JSON object has duplicate keys, the last one in the set will determine the value
12  *          of associative-array entries or struct fields.)
13  *     $(LI `BigInt` and large number parsing are not implemented currently, but all integral types
14  *          as well as minimal exact representations of many `double` values are supported.)
15  *   )
16  * 
17  * Authors:
18  *   $(LINK2 mailto:Marco.Leise@gmx.de, Marco Leise)
19  * 
20  * Copyright:
21  *   © 2017-2023 $(LINK2 mailto:Marco.Leise@gmx.de, Marco Leise), $(LINK2 mailto:etienne@cimons.com, Etienne Cimon)
22  * 
23  * License:
24  *   $(LINK2 https://mit-license.org/, The MIT License (MIT))
25  * 
26  **************************************************************************************************/
27 module fast.json;
28 
29 //import core.stdc.string;
30 import std.range;
31 import std.traits;
32 import memutils.ct : isTuple;
33 
34 import fast.buffer;
35 import fast.cstring;
36 import fast.internal.sysdef;
37 import fast.parsing;
38 import fast.format;
39 import fast.internal.helpers : logError, logInfo;
40 
41 nothrow:
42 @safe:
43 
44 /*******************************************************************************
45  * 
46  * Loads a JSON string and validates the used parts. This includes a UTF-8
47  * validation on strings.
48  *
49  * Params:
50  *   text = The string to load.
51  *
52  * Returns:
53  *   A `Json` struct.
54  *
55  **************************************/
56 auto parseJSON(ALLOC, uint vl = trustedSource, T:
57 	const(char)[])(T text) nothrow
58 {
59 	return Json!(ALLOC, vl, false)(text);
60 }
61 
62 /*******************************************************************************
63  * 
64  * Load a JSON string that is considered 100% correct. No checks will be
65  * performed, not even if you try to read a number as a string.
66  *
67  * Params:
68  *   text = The string to load.
69  *
70  * Returns:
71  *   A `Json` struct.
72  *
73  **************************************/
74 auto parseTrustedJSON(ALLOC, T:
75 	const(char)[])(T text) nothrow
76 {
77 	return Json!(ALLOC, trustedSource, false)(text);
78 }
79 
80 /*******************************************************************************
81  *
82  * Validates a JSON string.
83  *
84  * Params:
85  *   text = The string to load.
86  *
87  * Returns:
88  *   true if verification failed
89  *
90  **************************************/
91 bool validateJSON(ALLOC, T:
92 	const(char)[])(T text)
93 {
94 	auto json = Json!(ALLOC, validateAll, true)(text);
95 	json.skipValue();
96 	return json.hasError();
97 }
98 
99 /// JSON data types returned by `peek`.
100 enum DataType : ubyte
101 {
102 	string,
103 	number,
104 	object,
105 	array,
106 	boolean,
107 	null_
108 }
109 
110 /// Validation strength of JSON parser
111 enum
112 {
113 	trustedSource, /// Assume 100% correct JSON and speed up parsing.
114 	validateUsed, /// Ignore errors in skipped portions.
115 	validateAll, /// Do a complete validation of the JSON data.
116 }
117 
118 /// A UDA used to remap enum members or struct field names to JSON strings.
119 struct JsonMapping
120 {
121 	string[string] map;
122 }
123 /// A UDA for including fields in serialization
124 struct serialize
125 {
126 }
127 
128 /// JSON parser state returned by the `state` property.
129 struct JsonParserState
130 {
131 	const(char)* text;
132 	size_t textlen;
133 	size_t nesting;
134 }
135 
136 /*******************************************************************************
137  * 
138  * This is a forward JSON parser for picking off items of interest on the go.
139  * It neither produces a node structure, nor does it produce events. Instead you
140  * can peek at the value type that lies ahead and/or directly consume a JSON
141  * value from the parser. Objects and arrays can be iterated over via `foreach`,
142  * while you can also directly ask for one or multiple keys of an object.
143  * 
144  * Prams:
145  *   vl = Validation level. Any of `trustedSource`, `validateUsed` or
146  *        `validateAll`.
147  *   validateUtf8 = If validation is enabled, this also checks UTF-8 encoding
148  *                  of JSON strings.
149  * 
150  **************************************/
151 struct Json(ALLOC, uint vl = validateUsed, bool validateUtf8 = vl > trustedSource)
152 		if ((vl > trustedSource || !validateUtf8))
153 {
154 nothrow:
155 @trusted:
156 private:
157 
158 	enum isTrusted = vl == trustedSource;
159 	enum skipAllInter = false;
160 	enum isValidating = vl >= validateUsed;
161 	enum isValidateAll = vl == validateAll;
162 
163 	const(char*) m_start = void;
164 	const(char)* m_text = void;
165 	size_t m_text_len = 0;
166 	size_t m_nesting = 0;
167 	ALLOC m_alloc;
168 	char[] m_buffer;
169 	bool m_isString = false;
170 	bool m_error = false;
171 
172 public:
173 	@property bool hasError()
174 	{
175 		return m_error;
176 	}
177 
178 	@disable this();
179 	@disable this(this);
180 
181 	/*******************************************************************************
182 	 * 
183 	 * Constructor taking a `string` for fast slicing.
184 	 * 
185 	 * JSON strings without escape sequences can be returned as slices.
186 	 *
187 	 * Params:
188 	 *   text = The JSON text to parse.
189 	 *   simdPrep = Set this to `No.simdPrep` to indicate that `text` is already
190 	 *     suffixed by 16 zero bytes as required for SIMD processing.
191 	 *
192 	 **************************************/
193 	nothrow
194 	this(string text, Flag!"simdPrep" simdPrep = Yes.simdPrep)
195 	{
196 		//import core.memory;
197 		m_isString = true;
198 		this(cast(const(char)[]) text, simdPrep);
199 	}
200 
201 	~this()
202 	{
203 		if (m_buffer.length > 0)
204 			m_alloc.deallocate(m_buffer);
205 	}
206 
207 	/*******************************************************************************
208 	 * 
209 	 * Constructor taking a `const char[]`.
210 	 * 
211 	 * JSON strings allocate on the GC heap when returned.
212 	 *
213 	 * Params:
214 	 *   text = The JSON text to parse.
215 	 *   simdPrep = Set this to `No.simdPrep` to indicate that `text` is already
216 	 *     suffixed by 16 zero bytes as required for SIMD processing.
217 	 *
218 	 **************************************/
219 	pure nothrow
220 	this(const(char)[] text, Flag!"simdPrep" simdPrep = Yes.simdPrep)
221 	{
222 		/*if (simdPrep)
223 		{
224 			// We need to append 16 zero bytes for SSE to work, and if that reallocates the char[]
225 			// we can declare it unique/immutable and don't need to allocate when returning JSON strings.
226 			auto oldPtr = text.ptr;
227 			text ~= "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0";
228 			m_isString |= oldPtr !is text.ptr;
229 		}*/
230 		m_start = m_text = text.ptr;
231 		m_text_len = text.length;
232 		skipWhitespace!false();
233 	}
234 
235 	/+
236 	 ╔══════════════════════════════════════════════════════════════════════════════
237 	 ║ ⚑ String
238 	 ╚══════════════════════════════════════════════════════════════════════════════
239 	 +/
240 
241 	/*******************************************************************************
242 	 * 
243 	 * Reads a string off the JSON text.
244 	 *
245 	 * Params:
246 	 *   allowNull = Allow `null` as a valid option for the string.
247 	 *
248 	 * Returns:
249 	 *   A GC managed string.
250 	 *
251 	 **************************************/
252 	string read(T)(bool allowNull = true) if (is(T == string))
253 	{
254 		if (!allowNull || peek == DataType..string)
255 		{
256 			auto borrowed = borrowString();
257 			return cast(string) borrowed;
258 		}
259 		return readNull();
260 	}
261 
262 	/*******************************************************************************
263 	 * 
264 	 * Reads an enumeration off the JSON text.
265 	 *
266 	 **************************************/
267 	T read(T)() if (is(T == enum))
268 	{
269 		enum mapping = buildRemapTable!T;
270 		auto oldPos = m_text;
271 		auto text = borrowString();
272 		foreach (m; mapping)
273 			if (text.length == m.json.length && memcmp(text.ptr, m.json.ptr, m.json.length) == 0)
274 				return m.d;
275 		m_text = oldPos;
276 		static if (isValidating)
277 		{
278 			handleError(format!"Could not find enum member `%s` in `%s`"(text, T.stringof));
279 		}
280 		assert(0);
281 	}
282 
283 	/*******************************************************************************
284 	 * 
285 	 * Reads a string off the JSON text with limited lifetime.
286 	 * 
287 	 * The reference to this slice is not guaranteed to be valid after the JSON
288 	 * parser has been destroyed or another object key or string value has been
289 	 * parsed. So make a copy before you continue parsing.
290 	 *
291 	 * Returns:
292 	 *   If the string had no escape sequences in it, the returned array is a
293 	 *   slice of the JSON text buffer, otherwise temporary copy.
294 	 *
295 	 **************************************/
296 	const(char)[] borrowString()
297 	{
298 		expect('"', "at start of string");
299 		auto escFreeStart = m_text;
300 
301 		if (scanString!validateUtf8())
302 		{
303 			// Fast path here is to return a slice of the JSON if it doesn't contain escapes.
304 			size_t length = m_text - escFreeStart;
305 			skipOnePlusWhitespace!skipAllInter();
306 			return escFreeStart[0 .. length];
307 		}
308 		else
309 		{
310 			// Otherwise we copy to a separate memory area managed by this parser instance.
311 			size_t len = 0;
312 			bool eos = false;
313 			char* mem_base = m_buffer.ptr;
314 			size_t mem_start_offset = m_buffer.length;
315 			goto CopyToBuffer;
316 			do
317 			{
318 				do
319 				{
320 					if (m_text - m_start > m_text_len + 1)
321 						return null;
322 					m_buffer = cast(char[]) m_alloc.reallocate(m_buffer, m_buffer.length + 4, false);
323 					mem_base = m_buffer.ptr + mem_start_offset;
324 					uint decoded = decodeEscape(mem_base + len);
325 					len += decoded;
326 				}
327 				while (*m_text == '\\');
328 
329 				escFreeStart = m_text;
330 				eos = scanString!validateUtf8();
331 			CopyToBuffer:
332 				size_t escFreeLength = m_text - escFreeStart;
333 
334 				if (escFreeLength > 0)
335 				{
336 
337 					m_buffer = cast(char[]) m_alloc.reallocate(m_buffer, m_buffer.length + escFreeLength, false);
338 
339 					mem_base = m_buffer.ptr + mem_start_offset;
340 					import ldc.intrinsics;
341 
342 					llvm_memcpy(mem_base + len, escFreeStart, escFreeLength);
343 					len += escFreeLength;
344 
345 				}
346 			}
347 			while (!eos);
348 			skipOnePlusWhitespace!skipAllInter();
349 			return mem_base[mem_start_offset .. mem_start_offset + len];
350 		}
351 	}
352 
353 	private bool scanString(bool validate)()
354 	{
355 		static if (validate)
356 		{
357 			import core.bitop;
358 
359 			while (true)
360 			{
361 				// Stop for control-characters, \, " and anything non-ASCII.
362 				m_text.seekToRanges!"\0\x1F\"\"\\\\\x7F\xFF";
363 
364 				// Handle printable ASCII range
365 				if (*m_text == '"')
366 					return true;
367 				if (*m_text == '\\')
368 					return false;
369 
370 				// Anything else better be UTF-8
371 				uint u = *cast(uint*) m_text;
372 				version (LittleEndian)
373 					u = bswap(u);
374 
375 				// Filter overlong ASCII and missing follow byte.
376 				if (
377 					(u & 0b111_00000_11_000000_00000000_00000000) == 0b110_00000_10_000000_00000000_00000000 &&
378 					(u > 0b110_00001_10_111111_11111111_11111111))
379 					m_text += 2;
380 				// Handle overlong representation, UTF-16 surrogate pairs and missing follow bytes.
381 		else if (
382 					(u & 0b1111_0000_11_000000_11_000000_00000000) == 0b1110_0000_10_000000_10_000000_00000000 &&
383 					(u & 0b0000_1111_00_100000_00_000000_00000000) != 0b0000_1101_00_100000_00_000000_00000000 &&
384 					(u > 0b1110_0000_10_011111_10_111111_11111111))
385 					m_text += 3;
386 				// Handle missing follow bytes, Handle overlong representation and out of valid range (max. 0x10FFFF)
387 		else if (
388 					(u & 0b11111_000_11_000000_11_000000_11_000000) == 0b11110_000_10_000000_10_000000_10_000000 &&
389 					(u > 0b11110_000_10_001111_10_111111_10_111111) && (
390 						u < 0b11110_100_10_010000_10_000000_10_000000))
391 					m_text += 4;
392 				// Handle invalid code units.
393 		else if (*m_text < ' ' || *m_text == 0x7F)
394 					expectNot("is a disallowed control character in strings");
395 				else if (*m_text >= 0x80 && *m_text <= 0xBF)
396 					expectNot("is a UTF-8 follow byte and cannot start a sequence");
397 				else
398 					expectNot("is not a valid UTF-8 sequence start");
399 			}
400 		}
401 		else
402 		{
403 			m_text.seekToAnyOf!("\\\"\0");
404 			return *m_text == '"';
405 		}
406 	}
407 
408 	private bool stringCompareCallback(ref immutable(char)* key, ref const(char)* str)
409 	{
410 		do
411 		{
412 			auto key4 = cast(char[4]*) key;
413 			char[4] buf = *key4;
414 			uint bytes = decodeEscape(buf.ptr);
415 			if (buf != *key4)
416 				return false;
417 			key += bytes;
418 		}
419 		while (str[0] == '\\');
420 		return true;
421 	}
422 
423 	private static immutable escapes = {
424 		char[256] result = '\0';
425 		result['"'] = '"';
426 		result['\\'] = '\\';
427 		result['/'] = '/';
428 		result['b'] = '\b';
429 		result['f'] = '\f';
430 		result['n'] = '\n';
431 		result['r'] = '\r';
432 		result['t'] = '\t';
433 		return result;
434 	}();
435 
436 	private void skipEscape()
437 	{
438 		static if (isValidateAll)
439 		{
440 			if (m_text[1] != 'u')
441 			{
442 				// Normal escape sequence. 2 bytes removed.
443 				if (!escapes[*++m_text])
444 					expectNot("in escape sequence");
445 				m_text++;
446 			}
447 			else
448 			{
449 				// UTF-16
450 				m_text += 2;
451 				decodeUtf16HexToCodepoint();
452 			}
453 		}
454 		else
455 			m_text += 2;
456 	}
457 
458 	private uint decodeEscape(scope char* dst)
459 	{
460 		if (m_text[1] != 'u')
461 		{
462 			// Normal escape sequence. 2 bytes removed.
463 			dst[0] = escapes[m_text[1]];
464 			static if (isValidating)
465 				if (!dst[0])
466 					handleError("Invalid escape sequence");
467 			m_text += 2;
468 			return 1;
469 		}
470 		else
471 		{
472 			// UTF-16
473 			m_text += 2;
474 			uint cp = decodeUtf16HexToCodepoint();
475 
476 			if (cp >= 0xD800 && cp <= 0xDBFF)
477 			{
478 				dst[0] = cast(char)(0b11110_000 | cp >> 18);
479 				dst[1] = cast(char)(0b10_000000 | cp >> 12 & 0b00_111111);
480 				dst[2] = cast(char)(0b10_000000 | cp >> 6 & 0b00_111111);
481 				dst[3] = cast(char)(0b10_000000 | cp & 0b00_111111);
482 				return 4;
483 			}
484 			else if (cp >= 0x800)
485 			{
486 				dst[0] = cast(char)(0b1110_0000 | cp >> 12);
487 				dst[1] = cast(char)(0b10_000000 | cp >> 6 & 0b00_111111);
488 				dst[2] = cast(char)(0b10_000000 | cp & 0b00_111111);
489 				return 3;
490 			}
491 			else if (cp >= 0x80)
492 			{
493 				dst[0] = cast(char)(0b110_00000 | cp >> 6);
494 				dst[1] = cast(char)(0b10_000000 | cp & 0b00_111111);
495 				return 2;
496 			}
497 			else if (cp <= 0x20)
498 			{
499 				dst[0] = '?';
500 				return 1;
501 			}
502 			else
503 			{
504 				dst[0] = cast(char)(cp);
505 				return 1;
506 			}
507 		}
508 	}
509 
510 	private dchar decodeUtf16HexToCodepoint()
511 	{
512 		import fast.internal.helpers;
513 
514 		uint cp, hi;
515 		foreach (i; staticIota!(0, 2))
516 		{
517 			static if (isValidating)
518 			{
519 				if (auto badByte = hexDecode4(m_text, cp))
520 				{
521 					m_text = badByte;
522 					expectNot("is not a hex digit");
523 				}
524 			}
525 			else
526 			{
527 				cp = hexDecode4(m_text);
528 			}
529 
530 			static if (i == 0)
531 			{
532 				// Is this a high surrogate (followed by a low surrogate) or not ?
533 				if (cp < 0xD800 || cp > 0xDBFF)
534 					break;
535 				hi = cp - 0xD800 + 0x40 << 10;
536 			}
537 			else static if (i == 1)
538 			{
539 				static if (isValidating)
540 				{
541 					if (cp < 0xDC00 || cp > 0xDFFF)
542 						handleError("The UTF-16 escape produced an invalid code point.");
543 					cp -= 0xDC00;
544 				}
545 				cp |= hi;
546 			}
547 		}
548 
549 		static if (isValidating)
550 			if (cp > 0x10FFFF || cp >= 0xD800 && cp <= 0xDFFF)
551 				handleError("The UTF-16 escape produced an invalid code point.");
552 
553 		return cp;
554 	}
555 
556 	private void skipString(bool skipInter)()
557 	{
558 		m_text++;
559 		skipRestOfString!skipInter();
560 	}
561 
562 	private void skipRestOfString(bool skipInter)()
563 	{
564 		while (!scanString!isValidateAll())
565 			skipEscape();
566 		skipOnePlusWhitespace!skipInter();
567 	}
568 
569 	/+
570 	 ╔══════════════════════════════════════════════════════════════════════════════
571 	 ║ ⚑ Number
572 	 ╚══════════════════════════════════════════════════════════════════════════════
573 	 +/
574 
575 	/*******************************************************************************
576 	 * 
577 	 * Reads a number off the JSON text.
578 	 * 
579 	 * If you ask for an unsigned value, no minus sign will be accepted in the JSON,
580 	 * otherwise all features of JSON numbers will be available. In particular large
581 	 * integers can be given in scientific notation.
582 	 *
583 	 * Params:
584 	 *   N = Built-in numerical type that should be returned.
585 	 *
586 	 * Returns:
587 	 *   The parsed number.
588 	 *
589 	 * Throws:
590 	 *   JSONException, on invalid JSON or integer overflow.
591 	 *
592 	 **************************************/
593 	N read(N)() if (isNumeric!N && !is(N == enum))
594 	{
595 		N n = void;
596 		static if (isUnsigned!N)
597 			enum NumberOptions opt = {};
598 		else
599 			enum NumberOptions opt = {minus: true};
600 		if (parseNumber!opt(m_text, n))
601 			skipWhitespace!skipAllInter();
602 		else static if (isValidating)
603 		{
604 			handleError(format!"Could not convert JSON number to `%s`"(N.stringof));
605 
606 		}
607 		return n;
608 	}
609 
610 	private string format(string fmt, ARGS...)(ARGS args) @trusted
611 	{
612 		import fast.format : formattedWrite, decCharsVal;
613 
614 		size_t size_estimate = fmt.length + 16;
615 		foreach (arg; args)
616 		{
617 			static if (is(typeof(arg) : char[]))
618 			{
619 				size_estimate += arg.length;
620 			}
621 			else static if (isIntegral!(typeof(arg)))
622 			{
623 				size_estimate += decCharsVal(arg);
624 			}
625 			else static if (isFloatingPoint!(typeof(arg)))
626 				size_estimate += decChars!(typeof(arg));
627 		}
628 		m_buffer = cast(char[]) m_alloc.reallocate(m_buffer, m_buffer.length + size_estimate, false);
629 		char* buf = m_buffer.ptr + m_buffer.length - size_estimate;
630 		string ret = cast(string) formattedWrite!fmt(buf, args);
631 
632 		return ret;
633 	}
634 
635 	private void skipNumber(bool skipInter)()
636 	{
637 		static if (isValidateAll)
638 		{
639 			if (*m_text == '-')
640 				m_text++;
641 			if (*m_text == '0')
642 				m_text++;
643 			else
644 				trySkipDigits();
645 			if (*m_text == '.')
646 			{
647 				m_text++;
648 				trySkipDigits();
649 			}
650 			if ((*m_text | 0x20) == 'e')
651 			{
652 				m_text++;
653 				if (*m_text == '+' || *m_text == '-')
654 					m_text++;
655 				trySkipDigits();
656 			}
657 			skipWhitespace!false();
658 		}
659 		else
660 		{
661 			m_text.skipCharRanges!"\t\n\r\r  ++-.09EEee";
662 			static if (skipInter)
663 				m_text.skipAllOf!"\t\n\r ,";
664 		}
665 	}
666 
667 	static if (isValidateAll)
668 	{
669 		private void trySkipDigits()
670 		{
671 			if (*m_text - '0' > 9)
672 				expectNot("in number literal");
673 			m_text.skipAllOf!"0123456789";
674 		}
675 	}
676 
677 	/+
678 	 ╔══════════════════════════════════════════════════════════════════════════════
679 	 ║ ⚑ Object
680 	 ╚══════════════════════════════════════════════════════════════════════════════
681 	 +/
682 
683 	/*******************************************************************************
684 	 * 
685 	 * Reads a plain old data struct off the JSON text.
686 	 *
687 	 * Params:
688 	 *   T = Type of struct that should be returned.
689 	 *
690 	 * Returns:
691 	 *   A struct of type `T`.
692 	 *
693 	 **************************************/
694 	T read(T)() if (is(T == struct) && __traits(isPOD, T))
695 	{
696 		nest('{', "on start of object");
697 
698 		T t;
699 		if (*m_text != '}')
700 			while (true)
701 			{
702 				auto key = borrowString();
703 				static if (!skipAllInter)
704 				{
705 					expect(':', "between key and value");
706 					if (m_error)
707 						return t;
708 					skipWhitespace!false();
709 				}
710 				import ldc.intrinsics;
711 
712 				enum mapping = buildRemapTable!T;
713 				foreach (m; mapping)
714 				{
715 					if (key.length == m.json.length && memcmp(key.ptr, m.json.ptr, m.json.length) == 0)
716 					{
717 						mixin("alias keyT = typeof(T." ~ m.d ~ ");");
718 						mixin("t." ~ m.d ~ " = read!keyT;");
719 						goto Success;
720 					}
721 				}
722 				skipValue();
723 
724 			Success:
725 				if (*m_text == '}')
726 					break;
727 
728 				static if (!skipAllInter)
729 				{
730 					expect(',', "between key-value pairs");
731 					if (m_error)
732 						return t;
733 					skipWhitespace!false();
734 				}
735 			}
736 
737 		unnest();
738 		return t;
739 	}
740 
741 	/*******************************************************************************
742 	 * 
743 	 * Reads a plain old data struct or `null` off the JSON text.
744 	 * 
745 	 * Params:
746 	 *   T = Type of struct pointer that should be returned.
747 	 *
748 	 * Returns:
749 	 *   A pointer to a newly filled struct of type `T` on the GC heap.
750 	 *
751 	 **************************************/
752 	T read(T)()
753 			if (is(PointerTarget!T == struct) && __traits(isPOD, PointerTarget!T))
754 	{
755 		if (peek == DataType.null_)
756 			return readNull();
757 		T tp = new PointerTarget!T;
758 		*tp = read!(PointerTarget!T)();
759 		return tp;
760 	}
761 
762 	/*******************************************************************************
763 	 * 
764 	 * Reads an associative-array off a JSON text.
765 	 * 
766 	 * The key type must be `string`, the value type can be any type otherwise
767 	 * supported by the parser.
768 	 *
769 	 * Params:
770 	 *   T = The type of AA to return.
771 	 *
772 	 * Returns:
773 	 *   A newly filled associative array.
774 	 *
775 	 **************************************/
776 	T read(T)() if (is(KeyType!T == string))
777 	{
778 		T aa;
779 		foreach (key; byKey)
780 			aa[m_isString ? cast(immutable) key: key.idup] = read!(ValueType!T)();
781 		return aa;
782 	}
783 
784 	/*******************************************************************************
785 	 * 
786 	 * An alias to the `singleKey` method. Instead of `json.singleKey!"something"`
787 	 * you can write `json.something`. Read the notes on `singleKey`.
788 	 *
789 	 **************************************/
790 	alias opDispatch = singleKey;
791 
792 	/*******************************************************************************
793 	 * 
794 	 * Skips all keys of an object except the first occurence with the given key
795 	 * name.
796 	 *
797 	 * Params:
798 	 *   name = the key name of interest
799 	 *
800 	 * Returns:
801 	 *   A temporary struct, a proxy to the parser, that will automatically seek to
802 	 *   the end of the current JSON object on destruction.
803 	 *
804 	 * Throws:
805 	 *   JSONException when the key is not found in the object or parsing errors
806 	 *   occur.
807 	 * 
808 	 * Note:
809 	 *   Since this is an on the fly parser, you can only get one key from an
810 	 *   object with this method. Use `keySwitch` or `foreach(key; json)` to get
811 	 *   values from multiple keys.
812 	 * 
813 	 * See_Also:
814 	 *   keySwitch
815 	 *
816 	 **************************************/
817 	@property SingleKey singleKey(string name)()
818 	{
819 		nest('{', "on start of object");
820 
821 		if (*m_text != '}')
822 			while (true)
823 			{
824 				auto key = borrowString();
825 				static if (!skipAllInter)
826 				{
827 					expect(':', "between key and value");
828 					skipWhitespace!false();
829 				}
830 
831 				if (key.length == name.length && memcmp(key.ptr, name.ptr, name.length) == 0)
832 					return SingleKey(this);
833 
834 				skipValueImpl!skipAllInter();
835 
836 				if (*m_text == '}')
837 					break;
838 
839 				static if (!skipAllInter)
840 				{
841 					expect(',', "between key-value pairs");
842 					skipWhitespace!false();
843 				}
844 			}
845 
846 		unnest();
847 		static if (isValidating)
848 			handleError("Key not found.");
849 		assert(0);
850 	}
851 
852 	/*******************************************************************************
853 	 * 
854 	 * Selects from a set of given keys in an object and calls the corresponding
855 	 * delegate. The difference to `singleKey` when invoked with a single key is
856 	 * that `keySwitch` will not error out if the key is non-existent and may
857 	 * trigger the delegate multiple times, if the JSON object has duplicate keys.
858 	 *
859 	 * Params:
860 	 *   Args = the names of the keys
861 	 *   dlg = the delegates corresponding to the keys
862 	 *
863 	 * Throws:
864 	 *   JSONException when the key is not found in the object or parsing errors
865 	 *   occur.
866 	 * 
867 	 **************************************/
868 	void keySwitch(Args...)(scope void delegate()[Args.length] dlg...) nothrow
869 	{
870 		nest('{', "on start of object");
871 
872 		if (*m_text != '}')
873 			while (true)
874 			{
875 				auto key = borrowString();
876 				static if (!skipAllInter)
877 				{
878 					expect(':', "between key and value");
879 					skipWhitespace!false();
880 				}
881 
882 				auto oldPos = m_text;
883 				foreach (i, arg; Args)
884 				{
885 					if (key.length == arg.length && memcmp(key.ptr, arg.ptr, arg.length) == 0)
886 					{
887 						(cast(void delegate() nothrow) dlg[i])();
888 						goto Next;
889 					}
890 				}
891 				skipValue();
892 
893 			Next:
894 				if (*m_text == '}')
895 					break;
896 
897 				static if (!skipAllInter)
898 					if (oldPos !is m_text)
899 						{
900 						expect(',', "after key-value pair");
901 						skipWhitespace!false();
902 					}
903 			}
904 
905 		unnest();
906 	}
907 
908 	private int byKeyImpl(scope int delegate(ref const char[]) foreachBody) nothrow
909 	{
910 		nest('{', "at start of foreach over object");
911 
912 		int result = 0;
913 		if (*m_text != '}')
914 			while (true)
915 			{
916 				auto key = borrowString();
917 				static if (!skipAllInter)
918 				{
919 					expect(':', "between key and value");
920 					skipWhitespace!false;
921 				}
922 
923 				if (iterationGuts!"{}"(result, key, cast(int delegate(ref const char[]) nothrow) foreachBody, "after key-value pair"))
924 					break;
925 			}
926 
927 		unnest();
928 		return result;
929 	}
930 
931 	/*******************************************************************************
932 	 * 
933 	 * Iterate the keys of a JSON object with `foreach`.
934 	 * 
935 	 * Notes:
936 	 *   $(UL
937 	 *     $(LI If you want to store the key, you need to duplicate it.)
938 	 *   )
939 	 * 
940 	 * Example:
941 	 * ---
942 	 * uint id;
943 	 * foreach (key; json.byKey)
944 	 *     if (key == "id")
945 	 *         id = json.read!uint;
946 	 * ---
947 	 **************************************/
948 	@trusted @nogc pure nothrow
949 	@property int delegate(scope int delegate(ref const char[]) nothrow) nothrow byKey()
950 	{
951 		return cast(int delegate(scope int delegate(ref const char[]) nothrow) nothrow)&byKeyImpl;
952 	}
953 
954 	/+
955 	 ╔══════════════════════════════════════════════════════════════════════════════
956 	 ║ ⚑ Array handling
957 	 ╚══════════════════════════════════════════════════════════════════════════════
958 	 +/
959 
960 	/*******************************************************************************
961 	 * 
962 	 * Reads a dynamic array off the JSON text.
963 	 * 
964 	 **************************************/
965 	T read(T)() if (isDynamicArray!T && !isSomeString!T)
966 	{
967 		Appender!T app;
968 		foreach (i; this)
969 			app.put(read!(typeof(T.init[0])));
970 		return app.data;
971 	}
972 
973 	/*******************************************************************************
974 	 * 
975 	 * Reads a static array off the JSON text.
976 	 * 
977 	 * When validation is enabled, it is an error if the JSON array has a different
978 	 * length lengths don't match up. Otherwise unset elements receive their initial
979 	 * value.
980 	 *
981 	 **************************************/
982 	T read(T)() if (isStaticArray!T)
983 	{
984 		T sa = void;
985 		size_t cnt;
986 		foreach (i; this)
987 		{
988 			if (i < T.length)
989 				sa[i] = read!(typeof(T.init[0]));
990 			cnt = i + 1;
991 		}
992 		static if (isValidating)
993 		{
994 			if (cnt != T.length)
995 			{
996 				handleError(format!"Static array size mismatch. Expected %d, got %d"(T.length, cnt));
997 			}
998 		}
999 		else
1000 		{
1001 			foreach (i; cnt .. T.length)
1002 				sa[i] = T.init;
1003 		}
1004 		return sa;
1005 	}
1006 
1007 	/*******************************************************************************
1008 	 * 
1009 	 * Iterate over a JSON array via `foreach`.
1010 	 *
1011 	 **************************************/
1012 	int opApply(scope int delegate(const size_t) foreachBody)
1013 	{
1014 		nest('[', "at start of foreach over array");
1015 
1016 		int result = 0;
1017 		if (*m_text != ']')
1018 			for (size_t idx = 0; true; idx++)
1019 				if (iterationGuts!"[]"(result, idx, cast(int delegate(const size_t) nothrow) foreachBody, "after array element"))
1020 					break;
1021 
1022 		unnest();
1023 		return result;
1024 	}
1025 
1026 	/+
1027 	 ╔══════════════════════════════════════════════════════════════════════════════
1028 	 ║ ⚑ Boolean
1029 	 ╚══════════════════════════════════════════════════════════════════════════════
1030 	 +/
1031 
1032 	/*******************************************************************************
1033 	 * 
1034 	 * Reads a boolean value off the JSON text.
1035 	 *
1036 	 **************************************/
1037 	bool read(T)() if (is(T == bool))
1038 	{
1039 		return skipBoolean!(skipAllInter, isValidating)();
1040 	}
1041 
1042 	private bool skipBoolean(bool skipInter, bool validate = isValidateAll)()
1043 	{
1044 		auto isFalse = *m_text == 'f';
1045 		static if (validate)
1046 		{
1047 			if (*cast(char[4]*) m_text != "true" && *cast(char[4]*) m_text != "fals")
1048 				handleError("`true` or `false` expected.");
1049 		}
1050 		m_text += isFalse ? 5 : 4;
1051 		skipWhitespace!skipInter();
1052 		return !isFalse;
1053 	}
1054 
1055 	/+
1056 	 ╔══════════════════════════════════════════════════════════════════════════════
1057 	 ║ ⚑ Null
1058 	 ╚══════════════════════════════════════════════════════════════════════════════
1059 	 +/
1060 
1061 	/*******************************************************************************
1062 	 * 
1063 	 * Reads `null` off the JSON text.
1064 	 *
1065 	 **************************************/
1066 	typeof(null) readNull()
1067 	{
1068 		skipNull!(skipAllInter, isValidating)();
1069 		return null;
1070 	}
1071 
1072 	private void skipNull(bool skipInter, bool validate = isValidateAll)()
1073 	{
1074 		static if (validate)
1075 			if (*cast(const uint*) m_text != *cast(const uint*) "null".ptr)
1076 				handleError("`null` expected.");
1077 		m_text += 4;
1078 		skipWhitespace!skipInter();
1079 	}
1080 
1081 	/+
1082 	 ╔══════════════════════════════════════════════════════════════════════════════
1083 	 ║ ⚑ Helpers and Error Handling
1084 	 ╚══════════════════════════════════════════════════════════════════════════════
1085 	 +/
1086 
1087 	/*******************************************************************************
1088 	 * 
1089 	 * Skips the next JSON value if you are not interested.
1090 	 *
1091 	 **************************************/
1092 	void skipValue()
1093 	{
1094 		skipValueImpl!skipAllInter();
1095 	}
1096 
1097 	private void skipValueImpl(bool skipInter)()
1098 	{
1099 		with (DataType) switch (peek)
1100 		{
1101 		case string:
1102 			skipString!skipInter();
1103 			break;
1104 		case number:
1105 			skipNumber!skipInter();
1106 			break;
1107 		case object:
1108 			static if (isValidateAll)
1109 			{
1110 				foreach (_; this.byKey)
1111 					break;
1112 			}
1113 			else
1114 			{
1115 				m_text++;
1116 				seekObjectEnd();
1117 				skipOnePlusWhitespace!skipInter();
1118 			}
1119 			break;
1120 		case array:
1121 			static if (isValidateAll)
1122 			{
1123 				foreach (_; this)
1124 					break;
1125 			}
1126 			else
1127 			{
1128 				m_text++;
1129 				seekArrayEnd();
1130 				skipOnePlusWhitespace!skipInter();
1131 			}
1132 			break;
1133 		case boolean:
1134 			skipBoolean!skipInter();
1135 			break;
1136 		case null_:
1137 			skipNull!skipInter();
1138 			break;
1139 		default:
1140 
1141 			break;
1142 		}
1143 	}
1144 
1145 	/*******************************************************************************
1146 	 * 
1147 	 * Returns the type of data that is up next in the JSON text.
1148 	 *
1149 	 **************************************/
1150 	@property DataType peek()
1151 	{
1152 		static immutable trans = {
1153 			DataType[256] result = cast(DataType) ubyte.max;
1154 			result['{'] = DataType.object;
1155 			result['['] = DataType.array;
1156 			result['-'] = DataType.number;
1157 			foreach (i; '0' .. '9' + 1)
1158 				result[i] = DataType.number;
1159 			result['"'] = DataType..string;
1160 			result['t'] = DataType.boolean;
1161 			result['f'] = DataType.boolean;
1162 			result['n'] = DataType.null_;
1163 			return result;
1164 		}();
1165 
1166 		DataType vt = trans[*m_text];
1167 		static if (isValidating)
1168 			if (vt == ubyte.max)
1169 				expectNot("while peeking at next value type");
1170 		return vt;
1171 	}
1172 
1173 	/*******************************************************************************
1174 	 *
1175 	 * Save or restore the parser's internal state.
1176 	 *
1177 	 * If you want to read only a certain object from the JSON, but exactly which
1178 	 * depends on the value of some key, this is where saving and restoring the
1179 	 * parser state helps.
1180 	 *
1181 	 * Before each candidate you save the parser state. Then you perform just the
1182 	 * minimal work to test if the candidate matches some criteria. If it does,
1183 	 * restore the parser state and read the elements in full. Of it doesn't, just
1184 	 * skip to the next.
1185 	 *
1186 	 **************************************/
1187 	@property const(JsonParserState) state() const
1188 	{
1189 		return JsonParserState(m_text, m_text_len, m_nesting);
1190 	}
1191 
1192 	@property void state(const JsonParserState oldState)
1193 	{
1194 		m_text = oldState.text;
1195 		m_text_len = oldState.textlen;
1196 		m_nesting = oldState.nesting;
1197 	}
1198 
1199 	private void nest(char c, string msg)
1200 	{
1201 		expect(c, msg);
1202 		skipWhitespace!false();
1203 		m_nesting++;
1204 	}
1205 
1206 	private void unnest()
1207 	in
1208 	{
1209 		assert(m_nesting > 0);
1210 	}
1211 	body
1212 	{
1213 		if (--m_nesting == 0)
1214 		{
1215 			skipOnePlusWhitespace!false();
1216 			static if (isValidating)
1217 				if (*m_text != '\0') //
1218 					handleError("Expected end of JSON.");
1219 		}
1220 		else
1221 			skipOnePlusWhitespace!skipAllInter();
1222 	}
1223 
1224 	private bool iterationGuts(char[2] braces, T, D)(ref int result, T idx, scope D dlg,
1225 		string missingCommaMsg)
1226 	{
1227 		auto oldPos = m_text;
1228 		static if (isValidateAll)
1229 		{
1230 			if (result)
1231 			{
1232 				skipValueImpl!(!isValidateAll)();
1233 				goto PastValue;
1234 			}
1235 		}
1236 		result = dlg(idx);
1237 		if (oldPos is m_text)
1238 			skipValueImpl!false();
1239 
1240 	PastValue:
1241 		if (*m_text == braces[1])
1242 			return true;
1243 
1244 		static if (!isValidateAll)
1245 			if (result)
1246 				{
1247 				seekAggregateEnd!braces();
1248 				return true;
1249 			}
1250 
1251 		static if (!skipAllInter)
1252 			if (oldPos !is m_text)
1253 				{
1254 				expect(',', missingCommaMsg);
1255 				skipWhitespace!false();
1256 			}
1257 		return false;
1258 	}
1259 
1260 	static if (!isValidateAll)
1261 	{
1262 		private void seekObjectEnd()
1263 		{
1264 			seekAggregateEnd!"{}"();
1265 		}
1266 
1267 		private void seekArrayEnd()
1268 		{
1269 			seekAggregateEnd!"[]"();
1270 		}
1271 
1272 		private void seekAggregateEnd(immutable char[2] parenthesis)()
1273 		{
1274 			size_t nesting = 1;
1275 			while (m_text - m_start < m_text_len + 1)
1276 			{
1277 				m_text.seekToAnyOf!(parenthesis ~ "\"\0");
1278 				final switch (*m_text)
1279 				{
1280 				case parenthesis[0]:
1281 					m_text++;
1282 					nesting++;
1283 					break;
1284 				case parenthesis[1]:
1285 					if (--nesting == 0)
1286 						return;
1287 					m_text++;
1288 					break;
1289 				case '"':
1290 					// Could skip ':' or ',' here by passing `true`, but we skip it above anyways.
1291 					skipString!false();
1292 					break;
1293 				case '\0':
1294 					return;
1295 				}
1296 			}
1297 		}
1298 	}
1299 
1300 	/// This also increments the JSON read pointer.
1301 	private void expect(char c, string msg)
1302 	{
1303 		static if (isValidating)
1304 			if (*m_text != c)
1305 				expectImpl(c, msg);
1306 		m_text++;
1307 	}
1308 
1309 	private void expectNot(char c, string msg)
1310 	{
1311 		static if (isValidating)
1312 			if (*m_text == c)
1313 				expectNot(msg);
1314 	}
1315 
1316 	static if (isValidating)
1317 	{
1318 		@noinline
1319 		private void expectNot(string msg)
1320 		{
1321 			string error_msg;
1322 			if (isPrintable(*m_text))
1323 				error_msg = format!"Character '%s' %s."(*m_text, msg);
1324 			else
1325 				error_msg = format!"Byte %d %s."(*m_text, msg);
1326 			handleError(error_msg);
1327 		}
1328 
1329 		@noinline
1330 		private void expectImpl(char c, string msg)
1331 		{
1332 			string error_msg;
1333 			if (isPrintable(*m_text))
1334 				error_msg = format!"Expected '%s', but found '%s' %s."(c, *m_text, msg);
1335 			else
1336 				error_msg = format!"Expected '%s', but found byte %d %s."(c, *m_text, msg);
1337 			handleError(error_msg);
1338 		}
1339 
1340 		@noinline
1341 		private void handleError(T)(T msg)
1342 		{
1343 			m_error = true;
1344 			import fast.unicode;
1345 
1346 			size_t line;
1347 			const(char)* p = m_start;
1348 			const(char)* last = m_start;
1349 			while (p < m_text)
1350 			{
1351 				last = p;
1352 				p.skipToNextLine();
1353 				line++;
1354 			}
1355 			line += p is m_text;
1356 			size_t column = last[0 .. m_text - last].countGraphemes() + 1;
1357 
1358 			logError(format!"%s line %d col %d"(msg, line, column));
1359 			//while (*m_text != '\0') m_text++;
1360 		}
1361 	}
1362 
1363 	@forceinline @nogc pure nothrow
1364 	private void skipOnePlusWhitespace(bool skipInter)()
1365 	{
1366 		m_text++;
1367 		skipWhitespace!skipInter();
1368 	}
1369 
1370 	@forceinline @nogc pure nothrow
1371 	private void skipWhitespace(bool skipInter)()
1372 	{
1373 		static if (skipInter)
1374 			m_text.skipAllOf!"\t\n\r ,:";
1375 		else
1376 			m_text.skipAsciiWhitespace();
1377 	}
1378 
1379 	private static struct SingleKey
1380 	{
1381 		alias json this;
1382 
1383 		private Json* m_pjson;
1384 		private const(char*) m_oldPos;
1385 
1386 		@safe @nogc pure nothrow
1387 		@property ref Json json()
1388 		{
1389 			return *m_pjson;
1390 		}
1391 
1392 		this(ref Json json)
1393 		{
1394 			m_pjson = &json;
1395 			m_oldPos = json.m_text;
1396 		}
1397 
1398 		~this()
1399 		{
1400 			static if (isValidateAll)
1401 			{
1402 				if (*json.m_text != '}')
1403 				{
1404 					if (m_oldPos !is json.m_text)
1405 					{
1406 						json.expect(',', "after key-value pair");
1407 						json.skipWhitespace!false();
1408 					}
1409 					while (true)
1410 					{
1411 						json.skipString!false();
1412 						json.expect(':', "between key and value");
1413 						json.skipWhitespace!false();
1414 						json.skipValueImpl!false();
1415 
1416 						if (*json.m_text == '}')
1417 							break;
1418 
1419 						json.expect(',', "after key-value pair");
1420 						json.skipWhitespace!false();
1421 					}
1422 				}
1423 			}
1424 			else
1425 			{
1426 				json.seekObjectEnd();
1427 			}
1428 			json.unnest();
1429 		}
1430 	}
1431 
1432 }
1433 
1434 private template buildRemapTable(T)
1435 {
1436 	import std.typetuple;
1437 	import fast.internal.helpers;
1438 
1439 	static if (is(T == enum))
1440 	{
1441 		struct Remap
1442 		{
1443 			T d;
1444 			string json;
1445 		}
1446 
1447 		enum members = EnumMembers!T;
1448 	}
1449 	else
1450 	{
1451 		struct Remap
1452 		{
1453 			string d;
1454 			string json;
1455 		}
1456 
1457 		enum members = FieldNameTuple!T;
1458 	}
1459 	enum mapping = getUDA!(T, JsonMapping).map;
1460 
1461 	template Impl(size_t a, size_t b)
1462 	{
1463 		static if (b - a > 1)
1464 		{
1465 			alias Impl = TypeTuple!(Impl!(a, (b + a) / 2), Impl!((b + a) / 2, b));
1466 		}
1467 		else static if (b - a == 1)
1468 		{
1469 			static if (is(T == enum))
1470 				enum key = members[a].to!string;
1471 			else
1472 				alias key = members[a];
1473 			static if ((key in mapping) !is null)
1474 				enum mapped = mapping[key];
1475 			else
1476 				alias mapped = key;
1477 			alias Impl = TypeTuple!(Remap(members[a], mapped));
1478 		}
1479 		else
1480 			alias Impl = TypeTuple!();
1481 	}
1482 
1483 	alias buildRemapTable = Impl!(0, members.length);
1484 }
1485 
1486 size_t serializationLength(T)(T t) nothrow @trusted
1487 		if (is(T == struct) && !hasMember!(T, "opSlice") && !hasMember!(T, "get") && !isTuple!T)
1488 {
1489 	size_t len;
1490 	import std.traits : hasUDA;
1491 
1492 	len++; // {
1493 	static foreach (sym; T.tupleof)
1494 	{
1495 		{
1496 			enum isPublic = __traits(getProtection, sym) == "public";
1497 			static assert(!hasUDA!(sym, serialize) || (isPublic && hasUDA!(sym, serialize)), "Protected field has @serialize UDA");
1498 			static if (isPublic && hasUDA!(sym, serialize))
1499 			{
1500 				if (len > 1)
1501 					len += 4; // ,"":
1502 				else
1503 					len += 3; // "":
1504 				enum i = sym.stringof;
1505 				len += i.length;
1506 
1507 				static if (isPointer!(typeof(sym)))
1508 					len += serializationLength(*__traits(getMember, t, i));
1509 				else
1510 					len += serializationLength(__traits(getMember, t, i));
1511 
1512 			}
1513 		}
1514 	}
1515 	len++; // }
1516 	return len;
1517 }
1518 
1519 // hashmap
1520 size_t serializationLength(T)(T t) nothrow @trusted
1521 		if (is(T == struct) && hasMember!(T, "get") && hasMember!(T, "opApply") && !isTuple!T)
1522 {
1523 	size_t len;
1524 	len++; // {
1525 	foreach (key, ref val; t)
1526 	{
1527 		if (len > 1)
1528 			len++; // ,	
1529 
1530 		static if (isPointer!(typeof(key)))
1531 			len += serializationLength(*key);
1532 		else
1533 			len += serializationLength(key);
1534 
1535 		len++; // :
1536 
1537 		static if (isPointer!(typeof(val)))
1538 			len += serializationLength(*val);
1539 		else
1540 			len += serializationLength(val);
1541 
1542 	}
1543 
1544 	len++; // }
1545 	return len;
1546 }
1547 
1548 size_t serializationLength(T)(T t) nothrow @trusted
1549 		if ((isArray!T || (is(T == struct) && hasMember!(T, "opSlice")) || isTuple!T) && !isSomeString!T)
1550 {
1551 	size_t len;
1552 	len++; // [
1553 	foreach (i, v; t)
1554 	{
1555 		if (i > 0)
1556 		{
1557 			len++; // ,
1558 		}
1559 		static if (isPointer!(typeof(v)))
1560 			len += serializationLength(*v);
1561 		else
1562 			len += serializationLength(v);
1563 	}
1564 	len++; // ]
1565 	return len;
1566 }
1567 
1568 private size_t serializationLength(T)(T t) nothrow @trusted
1569 		if (isIntegral!T && !isFloatingPoint!T)
1570 {
1571 	import fast.format : decCharsVal;
1572 
1573 	char[8] buf;
1574 	char* bufptr = buf.ptr;
1575 	auto ret = bufptr.formattedWrite!"%d"(decCharsVal(t));
1576 
1577 	return decCharsVal(t);
1578 }
1579 
1580 private bool hasEscape(char c)
1581 {
1582 	if ((c <= 0x1F && c > 0xC) || (c > 0x1F && c != '"' && c != '\\'))
1583 		return false;
1584 	else if (c == '\t')
1585 		return true;
1586 	else if (c == '\b')
1587 		return true;
1588 	else if (c == '\n')
1589 		return true;
1590 	else if (c == '\r')
1591 		return true;
1592 	else if (c == '"')
1593 		return true;
1594 	else if (c == '\\')
1595 		return true;
1596 	else
1597 		return false; // '?'
1598 }
1599 
1600 private size_t serializationLength(T)(T t) nothrow @trusted if (isSomeString!T)
1601 {
1602 	import fast.format : formattedWrite, indexOf;
1603 
1604 	size_t i;
1605 	ptrdiff_t idx;
1606 	T substr = t;
1607 	do
1608 	{
1609 		idx = substr.indexOf("\"\t\r\n\\\b");
1610 		if (idx > -1)
1611 		{
1612 			i++;
1613 			substr = substr[idx + 1 .. $];
1614 		}
1615 	}
1616 	while (idx > -1);
1617 	return i + (cast(void[]) t).length + 2; // escapes + strlen + quotes
1618 }
1619 
1620 private size_t serializationLength(T)(T t) nothrow @trusted if (isFloatingPoint!T)
1621 {
1622 	import fast.format : decCharsVal;
1623 
1624 	return decCharsVal(t); // todo: optimize this
1625 }
1626 
1627 private size_t serializationLength(T)(T t) nothrow @trusted if (isBoolean!T)
1628 {
1629 	return t ? 4 : 5; // true : false
1630 }
1631 
1632 char[] serializeJSON(T)(char[] buf, T t) nothrow @trusted
1633 		if (is(T == struct) && !hasMember!(T, "opSlice") && !hasMember!(T, "get") && !isTuple!T)
1634 {
1635 	import std.traits : hasUDA;
1636 
1637 	char* buf_start = buf.ptr;
1638 	size_t offset;
1639 	char[] written = formattedWrite!"{"(buf.ptr + offset);
1640 	offset += written.length;
1641 	static foreach (sym; T.tupleof)
1642 	{
1643 		{
1644 			enum isPublic = __traits(getProtection, sym) == "public";
1645 			static assert(!hasUDA!(sym, serialize) || (isPublic && hasUDA!(sym, serialize)), "Protected field has @serialize UDA");
1646 			static if (isPublic && hasUDA!(sym, serialize))
1647 			{
1648 				alias ChildType = typeof(sym);
1649 				enum i = sym.stringof;
1650 				if (offset > 1)
1651 					written = formattedWrite!`,"%S":`(buf.ptr + offset, i);
1652 				else
1653 					written = formattedWrite!`"%S":`(buf.ptr + offset, i);
1654 
1655 				offset += written.length;
1656 				static if (isPointer!(typeof(sym)))
1657 					written = serializeJSON(buf[offset .. $], *__traits(getMember, t, i));
1658 				else
1659 					written = serializeJSON(buf[offset .. $], __traits(getMember, t, i));
1660 				// todo: Add hashmap
1661 				offset += written.length;
1662 			}
1663 		}
1664 	}
1665 	written = formattedWrite!"}"(buf.ptr + offset);
1666 	offset += written.length;
1667 	return buf_start[0 .. offset];
1668 }
1669 
1670 char[] serializeJSON(T)(char[] buf, T t) nothrow @trusted
1671 		if (is(T == struct) && hasMember!(T, "get") && hasMember!(T, "opApply") && !isTuple!T)
1672 {
1673 	char* buf_start = buf.ptr;
1674 	size_t offset;
1675 	char[] written = formattedWrite!"{"(buf.ptr + offset);
1676 	offset += written.length;
1677 	foreach (key, ref val; t)
1678 	{
1679 		if (offset > 1)
1680 		{
1681 			written = formattedWrite!`,`(buf.ptr + offset);
1682 			offset += written.length;
1683 		}
1684 
1685 		static if (isPointer!(typeof(key)))
1686 			written = serializeJSON(buf[offset .. $], *key);
1687 		else
1688 			written = serializeJSON(buf[offset .. $], key);
1689 
1690 		offset += written.length;
1691 
1692 		written = formattedWrite!`:`(buf.ptr + offset);
1693 
1694 		offset += written.length;
1695 		static if (isPointer!(typeof(val)))
1696 			written = serializeJSON(buf[offset .. $], *val);
1697 		else
1698 			written = serializeJSON(buf[offset .. $], val);
1699 
1700 		offset += written.length;
1701 	}
1702 
1703 	written = formattedWrite!"}"(buf.ptr + offset);
1704 	offset += written.length;
1705 	return buf_start[0 .. offset];
1706 }
1707 
1708 private char[] serializeJSON(T)(char[] buf, T t) nothrow @trusted
1709 		if ((isArray!T || (is(T == struct) && hasMember!(T, "opSlice")) || isTuple!T) && !isSomeString!T)
1710 {
1711 	char* buf_start = buf.ptr;
1712 	size_t offset;
1713 	char[] written = formattedWrite!"["(buf.ptr + offset, t);
1714 	offset += written.length;
1715 	foreach (i, v; t)
1716 	{
1717 		if (i > 0)
1718 		{
1719 			written = formattedWrite!`,`(buf.ptr + offset);
1720 			offset += written.length;
1721 		}
1722 		static if (isPointer!(typeof(v)))
1723 			written = serializeJSON(buf[offset .. $], *v);
1724 		else
1725 			written = serializeJSON(buf[offset .. $], v);
1726 		offset += written.length;
1727 	}
1728 	written = formattedWrite!"]"(buf.ptr + offset, t);
1729 	offset += written.length;
1730 	return buf_start[0 .. offset];
1731 }
1732 
1733 private char[] serializeJSON(T)(char[] buf, T t) nothrow @trusted
1734 		if (isIntegral!T && !isFloatingPoint!T)
1735 {
1736 	char[] written = formattedWrite!"%d"(buf.ptr, t);
1737 	return buf[0 .. written.length];
1738 }
1739 
1740 private char[] serializeJSON(T)(char[] buf, T t) nothrow @trusted
1741 		if (isSomeString!T)
1742 {
1743 	// escape string..?	
1744 	char[] written = formattedWrite!`"%S"`(buf.ptr, t);
1745 	return buf[0 .. written.length];
1746 }
1747 
1748 private char[] serializeJSON(T)(char[] buf, T t) nothrow @trusted
1749 		if (isFloatingPoint!T)
1750 {
1751 	char[] written = formattedWrite!`%f`(buf.ptr, t);
1752 	return buf[0 .. written.length];
1753 }
1754 
1755 private char[] serializeJSON(T)(char[] buf, T t) nothrow @trusted if (isBoolean!T)
1756 {
1757 	char[] written = t ? formattedWrite!`true`(buf.ptr) : formattedWrite!`false`(buf.ptr);
1758 	return buf[0 .. written.length];
1759 }
1760 
1761 unittest
1762 {
1763 	struct Counter
1764 	{
1765 		size_t array, object, key, string, number, boolean, null_;
1766 	}
1767 
1768 	void valueHandler(ref Json!validateAll.File json, ref Counter ctr)
1769 	{
1770 		with (DataType) final switch (json.peek)
1771 		{
1772 		case array:
1773 			ctr.array++;
1774 			foreach (_; json)
1775 				valueHandler(json, ctr);
1776 			break;
1777 		case object:
1778 			ctr.object++;
1779 			foreach (key; json.byKey)
1780 			{
1781 				ctr.key++;
1782 				valueHandler(json, ctr);
1783 			}
1784 			break;
1785 		case string:
1786 			ctr..string++;
1787 			json.skipValue();
1788 			break;
1789 		case number:
1790 			ctr.number++;
1791 			json.skipValue();
1792 			break;
1793 		case boolean:
1794 			ctr.boolean++;
1795 			json.skipValue();
1796 			break;
1797 		case null_:
1798 			ctr.null_++;
1799 			json.skipValue();
1800 			break;
1801 		}
1802 	}
1803 
1804 	// Tests that need to pass according to RFC 7159
1805 	passFile("test/pass1.json", Counter(6, 4, 33, 21, 32, 4, 2));
1806 	passFile("test/pass2.json", Counter(19, 0, 0, 1, 0, 0, 0));
1807 	passFile("test/pass3.json", Counter(0, 2, 3, 2, 0, 0, 0));
1808 	passFile("test/fail1.json", Counter(0, 0, 0, 1, 0, 0, 0));
1809 	passFile("test/fail18.json", Counter(20, 0, 0, 1, 0, 0, 0));
1810 
1811 	// Tests that need to fail
1812 	foreach (i; chain(iota(2, 18), iota(19, 34)))
1813 		failFile("test/fail" ~ i.to!string ~ ".json");
1814 
1815 	// Deserialization
1816 	struct Test
1817 	{
1818 		string text1;
1819 		string text2;
1820 		string text3;
1821 		double dbl = 0;
1822 		float flt = 0;
1823 		ulong ul;
1824 		uint ui;
1825 		ushort us;
1826 		ubyte ub;
1827 		long lm, lp;
1828 		int im, ip;
1829 		short sm, sp;
1830 		byte bm, bp;
1831 		bool t, f;
1832 		Test* tp1, tp2;
1833 		int[2] sa;
1834 		int[] da;
1835 		Test[string] aa;
1836 		SearchPolicy e;
1837 	}
1838 
1839 	Test t1 = {
1840 		text1: "abcde",
1841 		text2: "",
1842 		text3: null,
1843 		dbl: 1.1,
1844 		flt: -1.1,
1845 		ul: ulong.max,
1846 		ui: uint.max,
1847 		us: ushort.max,
1848 		ub: ubyte.max,
1849 		lm: long.min,
1850 		lp: long.max,
1851 		im: int.min,
1852 		ip: int.max,
1853 		sm: short.min,
1854 		sp: short.max,
1855 		bm: byte.min,
1856 		bp: byte.max,
1857 		t: true,
1858 		f: false,
1859 		tp1: null,
1860 		tp2: new Test("This is", "a", "test."),
1861 		sa: [33, 44],
1862 		da: [5, 6, 7],
1863 		aa: ["hash": Test("x", "y", "z")],
1864 		e: SearchPolicy.linear};
1865 		Test t2 = parseJSON(`{
1866 		"text1" : "abcde",
1867 		"text2" : "",
1868 		"text3" : null,
1869 		"dbl"   : 1.1,
1870 		"flt"   : -1.1,
1871 		"ul"    : `
1872 				~ ulong.max.to!string ~ `,
1873 		"ui"    : `
1874 				~ uint.max.to!string ~ `,
1875 		"us"    : `
1876 				~ ushort.max.to!string ~ `,
1877 		"ub"    : `
1878 				~ ubyte.max.to!string ~ `,
1879 		"lm"    : `
1880 				~ long.min.to!string ~ `,
1881 		"lp"    : `
1882 				~ long.max.to!string ~ `,
1883 		"im"    : `
1884 				~ int.min.to!string ~ `,
1885 		"ip"    : `
1886 				~ int.max.to!string ~ `,
1887 		"sm"    : `
1888 				~ short.min.to!string ~ `,
1889 		"sp"    : `
1890 				~ short.max.to!string ~ `,
1891 		"bm"    : `
1892 				~ byte.min.to!string ~ `,
1893 		"bp"    : `
1894 				~ byte.max.to!string ~ `,
1895 		"t"     : true,
1896 		"f"     : false,
1897 		"tp1"   : null,
1898 		"tp2"   : { "text1": "This is", "text2": "a", "text3": "test." },
1899 		"sa"    : [ 33, 44 ],
1900 		"da"    : [ 5, 6, 7 ],
1901 		"aa"    : { "hash" : { "text1":"x", "text2":"y", "text3":"z" } },
1902 		"e"     : "linear"
1903 	}`).read!Test;
1904 
1905 		assert(t2.tp2 && *t1.tp2 == *t2.tp2);
1906 		assert(t1.da == t2.da);
1907 		assert(t1.aa == t2.aa);
1908 		t2.tp2 = t1.tp2;
1909 		t2.da = t1.da;
1910 		t2.aa = t1.aa;
1911 		assert(t1 == t2);
1912 	}
1913 
1914 	// Test case for Issue #4
1915 	unittest
1916 	{
1917 		auto str = `{"initiator_carrier_code":null,"a":"b"}`;
1918 		auto js = parseTrustedJSON(str);
1919 		foreach (key; js.byKey)
1920 		{
1921 			if (key == "initiator_carrier_code")
1922 			{
1923 				auto t = js.read!string;
1924 				assert(t is null);
1925 			}
1926 		}
1927 	}
1928 
1929 	// Test case for Issue #5
1930 	unittest
1931 	{
1932 		import std.utf;
1933 
1934 		auto str = `{"a":"SΛNNO𐍈€한"}`;
1935 		str.validate;
1936 		validateJSON(str);
1937 	}