1 /**
2  * JSON encoding.
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.utils.json;
15 
16 import std.exception;
17 import std.math : isFinite;
18 import std.string;
19 import std.traits;
20 import std.typecons;
21 
22 import ae.utils.appender;
23 import ae.utils.array : isIdentical;
24 import ae.utils.exception;
25 import ae.utils.functor.primitives : functor;
26 import ae.utils.meta;
27 import ae.utils.textout;
28 
29 // ************************************************************************
30 
31 /// Basic JSON writer.
32 struct JsonWriter(Output)
33 {
34 	/// You can set this to something to e.g. write to another buffer.
35 	Output output;
36 
37 	private void putChars(S...)(S strings)
38 	{
39 		static if (is(typeof(output.putEx(strings))))
40 			output.putEx(strings);
41 		else
42 			foreach (str; strings)
43 				static if (is(typeof(output.put(str))))
44 					output.put(str);
45 				else
46 					foreach (dchar c; str)
47 					{
48 						alias C = char; // TODO: get char type of output
49 						C[4 / C.sizeof] buf = void;
50 						auto size = encode(buf, c);
51 						output.put(buf[0..size]);
52 					}
53 	}
54 
55 	/// Write a string literal.
56 	private void putString(C)(in C[] s)
57 	{
58 		// TODO: escape Unicode characters?
59 		// TODO: Handle U+2028 and U+2029 ( http://timelessrepo.com/json-isnt-a-javascript-subset )
60 
61 		output.putEx('"');
62 		auto start = s.ptr, p = start, end = start+s.length;
63 
64 		while (p < end)
65 		{
66 			auto c = *p++;
67 			if (c < Escapes.escaped.length && Escapes.escaped[c])
68 			{
69 				putChars(start[0..p-start-1], Escapes.chars[c]);
70 				start = p;
71 			}
72 		}
73 
74 		putChars(start[0..p-start], '"');
75 	}
76 
77 	/// Write a value of a simple type.
78 	void putValue(T)(T v)
79 	{
80 		static if (is(typeof(v is null)))
81 			if (v is null)
82 				return output.put("null");
83 		static if (is(T == typeof(null)))
84 			return output.put("null");
85 		else
86 		static if (isSomeString!T)
87 			putString(v);
88 		else
89 		static if (isSomeChar!(Unqual!T))
90 			return putString((&v)[0..1]);
91 		else
92 		static if (is(Unqual!T == bool))
93 			return output.put(v ? "true" : "false");
94 		else
95 		static if (is(Unqual!T : long))
96 			return .put(output, v);
97 		else
98 		static if (is(Unqual!T : real))
99 			if (v.isFinite)
100 				return output.putFP(v);
101 			else
102 				return putString(v.to!string);
103 		else
104 			static assert(0, "Don't know how to write " ~ T.stringof);
105 	}
106 
107 	void beginArray()
108 	{
109 		output.putEx('[');
110 	} ///
111 
112 	void endArray()
113 	{
114 		output.putEx(']');
115 	} ///
116 
117 	void beginObject()
118 	{
119 		output.putEx('{');
120 	} ///
121 
122 	void endObject()
123 	{
124 		output.putEx('}');
125 	} ///
126 
127 	void putKey(in char[] key)
128 	{
129 		putString(key);
130 		output.putEx(':');
131 	} ///
132 
133 	void putComma()
134 	{
135 		output.putEx(',');
136 	} ///
137 }
138 
139 /// JSON writer with indentation.
140 struct PrettyJsonWriter(Output, alias indent = '\t', alias newLine = '\n', alias pad = ' ')
141 {
142 	JsonWriter!Output jsonWriter; /// Underlying writer.
143 	alias jsonWriter this;
144 
145 	private bool indentPending;
146 	private uint indentLevel;
147 
148 	private void putIndent()
149 	{
150 		if (indentPending)
151 		{
152 			foreach (n; 0..indentLevel)
153 				output.putEx(indent);
154 			indentPending = false;
155 		}
156 	}
157 
158 	private void putNewline()
159 	{
160 		if (!indentPending)
161 		{
162 			output.putEx(newLine);
163 			indentPending = true;
164 		}
165 	}
166 
167 	void putValue(T)(T v)
168 	{
169 		putIndent();
170 		jsonWriter.putValue(v);
171 	} ///
172 
173 	void beginArray()
174 	{
175 		putIndent();
176 		jsonWriter.beginArray();
177 		indentLevel++;
178 		putNewline();
179 	} ///
180 
181 	void endArray()
182 	{
183 		indentLevel--;
184 		putNewline();
185 		putIndent();
186 		jsonWriter.endArray();
187 	} ///
188 
189 	void beginObject()
190 	{
191 		putIndent();
192 		jsonWriter.beginObject();
193 		indentLevel++;
194 		putNewline();
195 	} ///
196 
197 	void endObject()
198 	{
199 		indentLevel--;
200 		putNewline();
201 		putIndent();
202 		jsonWriter.endObject();
203 	} ///
204 
205 	void putKey(in char[] key)
206 	{
207 		putIndent();
208 		putString(key);
209 		output.putEx(pad, ':', pad);
210 	} ///
211 
212 	void putComma()
213 	{
214 		jsonWriter.putComma();
215 		putNewline();
216 	} ///
217 }
218 
219 /// Abstract JSON serializer based on `Writer`.
220 struct CustomJsonSerializer(Writer)
221 {
222 	Writer writer; /// Output.
223 
224 	/// Put a serializable value.
225 	void put(T)(auto ref T v)
226 	{
227 		static if (__traits(hasMember, T, "toJSON"))
228 			static if (is(typeof(v.toJSON())))
229 				put(v.toJSON());
230 			else
231 				v.toJSON((&this).functor!((self, ref j) => self.put(j)));
232 		else
233 		static if (is(T X == Nullable!X))
234 			if (v.isNull)
235 				writer.putValue(null);
236 			else
237 				put(v.get);
238 		else
239 		static if (is(T == enum))
240 			put(to!string(v));
241 		else
242 		static if (isSomeString!T || is(Unqual!T : real))
243 			writer.putValue(v);
244 		else
245 		static if (is(T == typeof(null)))
246 			writer.putValue(null);
247 		else
248 		static if (is(T U : U[]))
249 		{
250 			writer.beginArray();
251 			if (v.length)
252 			{
253 				put(v[0]);
254 				foreach (i; v[1..$])
255 				{
256 					writer.putComma();
257 					put(i);
258 				}
259 			}
260 			writer.endArray();
261 		}
262 		else
263 		static if (isTuple!T)
264 		{
265 			// TODO: serialize as object if tuple has names
266 			enum N = v.expand.length;
267 			static if (N == 0)
268 				return;
269 			else
270 			static if (N == 1)
271 				put(v.expand[0]);
272 			else
273 			{
274 				writer.beginArray();
275 				foreach (n; rangeTuple!N)
276 				{
277 					static if (n)
278 						writer.putComma();
279 					put(v.expand[n]);
280 				}
281 				writer.endArray();
282 			}
283 		}
284 		else
285 		static if (is(typeof(T.init.keys)) && is(typeof(T.init.values)) && is(typeof({string s = T.init.keys[0];})))
286 		{
287 			writer.beginObject();
288 			bool first = true;
289 			foreach (key, value; v)
290 			{
291 				if (!first)
292 					writer.putComma();
293 				else
294 					first = false;
295 				writer.putKey(key);
296 				put(value);
297 			}
298 			writer.endObject();
299 		}
300 		else
301 		static if (is(T==JSONFragment))
302 			writer.output.put(v.json);
303 		else
304 		static if (is(T==struct))
305 		{
306 			writer.beginObject();
307 			bool first = true;
308 			foreach (i, ref field; v.tupleof)
309 			{
310 				static if (!doSkipSerialize!(T, v.tupleof[i].stringof[2..$]))
311 				{
312 					static if (hasAttribute!(JSONOptional, v.tupleof[i]))
313 						if (isIdentical(v.tupleof[i], T.init.tupleof[i]))
314 							continue;
315 					if (!first)
316 						writer.putComma();
317 					else
318 						first = false;
319 					writer.putKey(getJsonName!(T, v.tupleof[i].stringof[2..$]));
320 					put(field);
321 				}
322 			}
323 			writer.endObject();
324 		}
325 		else
326 		static if (is(typeof(*v)))
327 		{
328 			if (v)
329 				put(*v);
330 			else
331 				writer.putValue(null);
332 		}
333 		else
334 			static assert(0, "Can't serialize " ~ T.stringof ~ " to JSON");
335 	}
336 }
337 
338 /// JSON serializer with `StringBuilder` output.
339 alias JsonSerializer = CustomJsonSerializer!(JsonWriter!StringBuilder);
340 
341 private struct Escapes
342 {
343 	static immutable  string[256] chars;
344 	static immutable bool[256] escaped;
345 
346 	shared static this()
347 	{
348 		import std.string : format;
349 
350 		escaped[] = true;
351 		foreach (c; 0..256)
352 			if (c=='\\')
353 				chars[c] = `\\`;
354 			else
355 			if (c=='\"')
356 				chars[c] = `\"`;
357 			else
358 			if (c=='\b')
359 				chars[c] = `\b`;
360 			else
361 			if (c=='\f')
362 				chars[c] = `\f`;
363 			else
364 			if (c=='\n')
365 				chars[c] = `\n`;
366 			else
367 			if (c=='\r')
368 				chars[c] = `\r`;
369 			else
370 			if (c=='\t')
371 				chars[c] = `\t`;
372 			else
373 			if (c<'\x20' || c == '\x7F' || c=='<' || c=='>' || c=='&')
374 				chars[c] = format(`\u%04x`, c);
375 			else
376 				chars[c] = [cast(char)c],
377 				escaped[c] = false;
378 	}
379 }
380 
381 // ************************************************************************
382 
383 /// Serialize `T` to JSON, and return the result as a string.
384 string toJson(T)(auto ref T v)
385 {
386 	JsonSerializer serializer;
387 	serializer.put(v);
388 	return serializer.writer.output.get();
389 }
390 
391 ///
392 debug(ae_unittest) unittest
393 {
394 	struct X { int a; string b; }
395 	X x = {17, "aoeu"};
396 	assert(toJson(x) == `{"a":17,"b":"aoeu"}`, toJson(x));
397 	int[] arr = [1,5,7];
398 	assert(toJson(arr) == `[1,5,7]`);
399 	assert(toJson(true) == `true`);
400 
401 	assert(toJson(tuple()) == ``);
402 	assert(toJson(tuple(42)) == `42`);
403 	assert(toJson(tuple(42, "banana")) == `[42,"banana"]`);
404 }
405 
406 debug(ae_unittest) unittest
407 {
408 	struct A
409 	{
410 	}
411 
412 	struct B
413 	{
414 		A[] a;
415 		deprecated alias a this;
416 		JSONFragment toJSON() const { return JSONFragment(`null`); }
417 	}
418 
419 	B b;
420 	b.toJson();
421 }
422 
423 // ************************************************************************
424 
425 /// Serialize `T` to a pretty (indented) JSON string.
426 string toPrettyJson(T)(T v)
427 {
428 	CustomJsonSerializer!(PrettyJsonWriter!StringBuilder) serializer;
429 	serializer.put(v);
430 	return serializer.writer.output.get();
431 }
432 
433 ///
434 debug(ae_unittest) unittest
435 {
436 	struct X { int a; string b; int[] c, d; }
437 	X x = {17, "aoeu", [1, 2, 3]};
438 	assert(toPrettyJson(x) ==
439 `{
440 	"a" : 17,
441 	"b" : "aoeu",
442 	"c" : [
443 		1,
444 		2,
445 		3
446 	],
447 	"d" : [
448 	]
449 }`, toPrettyJson(x));
450 }
451 
452 // ************************************************************************
453 
454 import std.ascii;
455 import std.utf;
456 import std.conv;
457 
458 import ae.utils.text;
459 
460 private struct JsonParser(C)
461 {
462 	C[] s;
463 	size_t p;
464 
465 	Unqual!C next()
466 	{
467 		enforce(p < s.length, "Out of data while parsing JSON stream");
468 		return s[p++];
469 	}
470 
471 	string readN(uint n)
472 	{
473 		string r;
474 		for (int i=0; i<n; i++)
475 			r ~= next();
476 		return r;
477 	}
478 
479 	Unqual!C peek()
480 	{
481 		enforce(p < s.length, "Out of data while parsing JSON stream");
482 		return s[p];
483 	}
484 
485 	@property bool eof() { return p == s.length; }
486 
487 	void skipWhitespace()
488 	{
489 		while (isWhite(peek()))
490 			p++;
491 	}
492 
493 	void expect(C c)
494 	{
495 		auto n = next();
496 		enforce(n==c, text("Expected ", c, ", got ", n));
497 	}
498 
499 	void read(T)(ref T value)
500 	{
501 		static if (is(T == typeof(null)))
502 			value = readNull();
503 		else
504 		static if (is(T X == Nullable!X))
505 			readNullable!X(value);
506 		else
507 		static if (is(T==enum))
508 			value = readEnum!(T)();
509 		else
510 		static if (isSomeString!T)
511 			value = readString().to!T;
512 		else
513 		static if (is(T==bool))
514 			value = readBool();
515 		else
516 		static if (is(T : real))
517 			value = readNumber!(T)();
518 		else
519 		static if (isDynamicArray!T)
520 			value = readArray!(typeof(T.init[0]))();
521 		else
522 		static if (isStaticArray!T)
523 			readStaticArray(value);
524 		else
525 		static if (isTuple!T)
526 			readTuple!T(value);
527 		else
528 		static if (is(typeof(T.init.keys)) && is(typeof(T.init.values)) && is(typeof(T.init.keys[0])==string))
529 			readAA!(T)(value);
530 		else
531 		static if (is(T==JSONFragment))
532 		{
533 			auto start = p;
534 			skipValue();
535 			value = JSONFragment(s[start..p]);
536 		}
537 		else
538 		static if (is(T U : U*))
539 			value = readPointer!T();
540 		else
541 		static if (__traits(hasMember, T, "fromJSON"))
542 		{
543 			alias Q = Parameters!(T.fromJSON)[0];
544 			Q tempValue;
545 			read!Q(tempValue);
546 			static if (is(typeof(value = T.fromJSON(tempValue))))
547 				value = T.fromJSON(tempValue);
548 			else
549 			{
550 				import core.lifetime : move;
551 				auto convertedValue = T.fromJSON(tempValue);
552 				move(convertedValue, value);
553 			}
554 		}
555 		else
556 		static if (is(T==struct))
557 			readObject!(T)(value);
558 		else
559 			static assert(0, "Can't decode " ~ T.stringof ~ " from JSON");
560 	}
561 
562 	void readTuple(T)(ref T value)
563 	{
564 		// TODO: serialize as object if tuple has names
565 		enum N = T.expand.length;
566 		static if (N == 0)
567 			return;
568 		else
569 		static if (N == 1)
570 			read(value.expand[0]);
571 		else
572 		{
573 			expect('[');
574 			foreach (n, ref f; value.expand)
575 			{
576 				static if (n)
577 					expect(',');
578 				read(f);
579 			}
580 			expect(']');
581 		}
582 	}
583 
584 	typeof(null) readNull()
585 	{
586 		expect('n');
587 		expect('u');
588 		expect('l');
589 		expect('l');
590 		return null;
591 	}
592 
593 	void readNullable(T)(ref Nullable!T value)
594 	{
595 		skipWhitespace();
596 		if (peek() == 'n')
597 		{
598 			readNull();
599 			value = Nullable!T();
600 		}
601 		else
602 		{
603 			if (value.isNull)
604 			{
605 				T subvalue;
606 				read!T(subvalue);
607 				value = subvalue;
608 			}
609 			else
610 				read!T(value.get());
611 		}
612 	}
613 
614 	C[] readSimpleString() /// i.e. without escapes
615 	{
616 		skipWhitespace();
617 		expect('"');
618 		auto start = p;
619 		while (true)
620 		{
621 			auto c = next();
622 			if (c=='"')
623 				break;
624 			else
625 			if (c=='\\')
626 				throw new Exception("Unexpected escaped character");
627 		}
628 		return s[start..p-1];
629 	}
630 
631 	C[] readString()
632 	{
633 		skipWhitespace();
634 		auto c = peek();
635 		if (c == '"')
636 		{
637 			next(); // '"'
638 			C[] result;
639 			auto start = p;
640 			while (true)
641 			{
642 				c = next();
643 				if (c=='"')
644 					break;
645 				else
646 				if (c=='\\')
647 				{
648 					result ~= s[start..p-1];
649 					switch (next())
650 					{
651 						case '"':  result ~= '"'; break;
652 						case '/':  result ~= '/'; break;
653 						case '\\': result ~= '\\'; break;
654 						case 'b':  result ~= '\b'; break;
655 						case 'f':  result ~= '\f'; break;
656 						case 'n':  result ~= '\n'; break;
657 						case 'r':  result ~= '\r'; break;
658 						case 't':  result ~= '\t'; break;
659 						case 'u':
660 						{
661 							wstring buf;
662 							goto Unicode_start;
663 
664 							while (s[p..$].startsWith(`\u`))
665 							{
666 								p+=2;
667 							Unicode_start:
668 								buf ~= cast(wchar)fromHex!ushort(readN(4));
669 							}
670 							result ~= buf.to!(C[]);
671 							break;
672 						}
673 						default: enforce(false, "Unknown escape");
674 					}
675 					start = p;
676 				}
677 			}
678 			result ~= s[start..p-1];
679 			return result;
680 		}
681 		else
682 		if (isDigit(c) || c=='-') // For languages that don't distinguish numeric strings from numbers
683 		{
684 			static immutable bool[256] numeric =
685 			[
686 				'0':true,
687 				'1':true,
688 				'2':true,
689 				'3':true,
690 				'4':true,
691 				'5':true,
692 				'6':true,
693 				'7':true,
694 				'8':true,
695 				'9':true,
696 				'.':true,
697 				'-':true,
698 				'+':true,
699 				'e':true,
700 				'E':true,
701 			];
702 
703 			auto start = p;
704 			while (numeric[c = peek()])
705 				p++;
706 			return s[start..p].dup;
707 		}
708 		else
709 		{
710 			foreach (n; "null")
711 				expect(n);
712 			return null;
713 		}
714 	}
715 
716 	bool readBool()
717 	{
718 		skipWhitespace();
719 		if (peek()=='t')
720 		{
721 			enforce(readN(4) == "true", "Bad boolean");
722 			return true;
723 		}
724 		else
725 		if (peek()=='f')
726 		{
727 			enforce(readN(5) == "false", "Bad boolean");
728 			return false;
729 		}
730 		else
731 		{
732 			ubyte i = readNumber!ubyte();
733 			enforce(i < 2, "Bad digit for implicit number-to-bool conversion");
734 			return !!i;
735 		}
736 	}
737 
738 	T readNumber(T)()
739 	{
740 		skipWhitespace();
741 		const(C)[] n;
742 		auto start = p;
743 		Unqual!C c = peek();
744 		if (c == '"')
745 			n = readSimpleString();
746 		else
747 		{
748 			while (c=='+' || c=='-' || (c>='0' && c<='9') || c=='e' || c=='E' || c=='.')
749 			{
750 				p++;
751 				if (eof) break;
752 				c = peek();
753 			}
754 			n = s[start..p];
755 		}
756 		static if (is(T : long))
757 			return to!T(n);
758 		else
759 		static if (is(T : real))
760 			return fpParse!T(n);
761 		else
762 			static assert(0, "Don't know how to parse numerical type " ~ T.stringof);
763 	}
764 
765 	T[] readArray(T)()
766 	{
767 		skipWhitespace();
768 		expect('[');
769 		skipWhitespace();
770 		T[] result;
771 		if (peek()==']')
772 		{
773 			p++;
774 			return result;
775 		}
776 		while(true)
777 		{
778 			T subvalue;
779 			read!T(subvalue);
780 			result ~= subvalue;
781 
782 			skipWhitespace();
783 			if (peek()==']')
784 			{
785 				p++;
786 				return result;
787 			}
788 			else
789 				expect(',');
790 		}
791 	}
792 
793 	void readStaticArray(T, size_t n)(ref T[n] value)
794 	{
795 		skipWhitespace();
796 		expect('[');
797 		skipWhitespace();
798 		foreach (i, ref subvalue; value)
799 		{
800 			if (i)
801 			{
802 				expect(',');
803 				skipWhitespace();
804 			}
805 			read(subvalue);
806 			skipWhitespace();
807 		}
808 		expect(']');
809 	}
810 
811 	void readObject(T)(ref T v)
812 	{
813 		skipWhitespace();
814 		expect('{');
815 		skipWhitespace();
816 		if (peek()=='}')
817 		{
818 			p++;
819 			return;
820 		}
821 
822 		while (true)
823 		{
824 			auto jsonField = readSimpleString();
825 			mixin(exceptionContext(q{"Error with field " ~ to!string(jsonField)}));
826 			skipWhitespace();
827 			expect(':');
828 
829 			bool found;
830 			foreach (i, ref field; v.tupleof)
831 			{
832 				enum name = getJsonName!(T, v.tupleof[i].stringof[2..$]);
833 				if (name == jsonField)
834 				{
835 					read(field);
836 					found = true;
837 					break;
838 				}
839 			}
840 
841 			if (!found)
842 			{
843 				static if (hasAttribute!(JSONPartial, T))
844 					skipValue();
845 				else
846 					throw new Exception(cast(string)("Unknown field " ~ jsonField));
847 			}
848 
849 			skipWhitespace();
850 			if (peek()=='}')
851 			{
852 				p++;
853 				return;
854 			}
855 			else
856 				expect(',');
857 		}
858 	}
859 
860 	void readAA(T)(ref T v)
861 	{
862 		skipWhitespace();
863 		static if (is(typeof(T.init is null)))
864 			if (peek() == 'n')
865 			{
866 				v = readNull();
867 				return;
868 			}
869 		expect('{');
870 		skipWhitespace();
871 		if (peek()=='}')
872 		{
873 			p++;
874 			return;
875 		}
876 		alias K = typeof(v.keys[0]);
877 
878 		while (true)
879 		{
880 			auto jsonField = readString();
881 			skipWhitespace();
882 			expect(':');
883 
884 			// TODO: elide copy
885 			typeof(v.values[0]) subvalue;
886 			read(subvalue);
887 			v[jsonField.to!K] = subvalue;
888 
889 			skipWhitespace();
890 			if (peek()=='}')
891 			{
892 				p++;
893 				return;
894 			}
895 			else
896 				expect(',');
897 		}
898 	}
899 
900 	T readEnum(T)()
901 	{
902 		return to!T(readSimpleString());
903 	}
904 
905 	T readPointer(T)()
906 	{
907 		skipWhitespace();
908 		if (peek()=='n')
909 		{
910 			enforce(readN(4) == "null", "Null expected");
911 			return null;
912 		}
913 		alias S = typeof(*T.init);
914 		T v = new S;
915 		read!S(*v);
916 		return v;
917 	}
918 
919 	void skipValue()
920 	{
921 		skipWhitespace();
922 		Unqual!C c = peek();
923 		switch (c)
924 		{
925 			case '"':
926 				readString(); // TODO: Optimize
927 				break;
928 			case '0': .. case '9':
929 			case '-':
930 				while (c=='+' || c=='-' || (c>='0' && c<='9') || c=='e' || c=='E' || c=='.')
931 				{
932 					p++;
933 					if (eof) break;
934 					c = peek();
935 				}
936 				break;
937 			case '{':
938 				next();
939 				skipWhitespace();
940 				bool first = true;
941 				while (peek() != '}')
942 				{
943 					if (first)
944 						first = false;
945 					else
946 						expect(',');
947 					skipValue(); // key
948 					skipWhitespace();
949 					expect(':');
950 					skipValue(); // value
951 					skipWhitespace();
952 				}
953 				expect('}');
954 				break;
955 			case '[':
956 				next();
957 				skipWhitespace();
958 				bool first = true;
959 				while (peek() != ']')
960 				{
961 					if (first)
962 						first = false;
963 					else
964 						expect(',');
965 					skipValue();
966 					skipWhitespace();
967 				}
968 				expect(']');
969 				break;
970 			case 't':
971 				foreach (l; "true")
972 					expect(l);
973 				break;
974 			case 'f':
975 				foreach (l; "false")
976 					expect(l);
977 				break;
978 			case 'n':
979 				foreach (l; "null")
980 					expect(l);
981 				break;
982 			default:
983 				throw new Exception(text("Can't parse: ", c));
984 		}
985 	}
986 }
987 
988 /// Parse the JSON in string `s` and deserialize it into an instance of `T`.
989 T jsonParse(T, C)(C[] s)
990 {
991 	auto parser = JsonParser!C(s);
992 	mixin(exceptionContext(q{format("Error at position %d", parser.p)}));
993 	T result;
994 	parser.read!T(result);
995 	return result;
996 }
997 
998 debug(ae_unittest) unittest
999 {
1000 	struct S { int i; S[] arr; S* p0, p1; }
1001 	S s = S(42, [S(1), S(2)], null, new S(15));
1002 	auto s2 = jsonParse!S(toJson(s));
1003 	//assert(s == s2); // Issue 3789
1004 	assert(s.i == s2.i && s.arr == s2.arr && s.p0 is s2.p0 && *s.p1 == *s2.p1);
1005 	jsonParse!S(toJson(s).dup);
1006 
1007 	assert(jsonParse!(Tuple!())(``) == tuple());
1008 	assert(jsonParse!(Tuple!int)(`42`) == tuple(42));
1009 	assert(jsonParse!(Tuple!(int, string))(`[42, "banana"]`) == tuple(42, "banana"));
1010 
1011 	assert(jsonParse!(string[string])(`null`) is null);
1012 }
1013 
1014 debug(ae_unittest) unittest
1015 {
1016 	struct T { string s; wstring w; dstring d; }
1017 	T t;
1018 	auto s = t.toJson;
1019 	assert(s == `{"s":null,"w":null,"d":null}`, s);
1020 
1021 	t.s = "foo";
1022 	t.w = "bar"w;
1023 	t.d = "baz"d;
1024 	s = t.toJson;
1025 	assert(s == `{"s":"foo","w":"bar","d":"baz"}`, s);
1026 
1027 	jsonParse!T(s);
1028 	jsonParse!T(cast(char[]) s);
1029 	jsonParse!T(cast(const(char)[]) s);
1030 	jsonParse!T(s.to!wstring);
1031 	jsonParse!T(s.to!dstring);
1032 }
1033 
1034 debug(ae_unittest) unittest
1035 {
1036 	jsonParse!(int[2])(`[ 1 , 2 ]`);
1037 }
1038 
1039 // NaNs and infinities are serialized as strings.
1040 debug(ae_unittest) unittest
1041 {
1042 	void check(double f, string s)
1043 	{
1044 		assert(f.toJson() == s);
1045 		assert(s.jsonParse!double is f);
1046 	}
1047 	check(double.init, `"nan"`);
1048 	check(double.infinity, `"inf"`);
1049 	check(-double.infinity, `"-inf"`);
1050 }
1051 
1052 /// Parse the JSON in string `s` and deserialize it into `T`.
1053 void jsonParse(T, C)(C[] s, ref T result)
1054 {
1055 	auto parser = JsonParser!C(s);
1056 	mixin(exceptionContext(q{format("Error at position %d", parser.p)}));
1057 	parser.read!T(result);
1058 }
1059 
1060 debug(ae_unittest) unittest
1061 {
1062 	struct S { int a, b; }
1063 	S s;
1064 	s.a = 1;
1065 	jsonParse(`{"b":2}`, s);
1066 	assert(s == S(1, 2));
1067 }
1068 
1069 // ************************************************************************
1070 
1071 // TODO: migrate to UDAs
1072 
1073 /**
1074  * A template that designates fields which should not be serialized to Json.
1075  *
1076  * Example:
1077  * ---
1078  * struct Point { int x, y, z; mixin NonSerialized!(x, z); }
1079  * assert(jsonParse!Point(toJson(Point(1, 2, 3))) == Point(0, 2, 0));
1080  * ---
1081  */
1082 template NonSerialized(fields...)
1083 {
1084 	import ae.utils.meta : stringofArray;
1085 	mixin(mixNonSerializedFields(stringofArray!fields()));
1086 }
1087 
1088 private string mixNonSerializedFields(string[] fields)
1089 {
1090 	string result;
1091 	foreach (field; fields)
1092 		result ~= "enum bool " ~ field ~ "_nonSerialized = 1;";
1093 	return result;
1094 }
1095 
1096 private template doSkipSerialize(T, string member)
1097 {
1098 	enum bool doSkipSerialize = __traits(hasMember, T, member ~ "_nonSerialized");
1099 }
1100 
1101 debug(ae_unittest) unittest
1102 {
1103 	struct Point { int x, y, z; mixin NonSerialized!(x, z); }
1104 	assert(jsonParse!Point(toJson(Point(1, 2, 3))) == Point(0, 2, 0));
1105 }
1106 
1107 debug(ae_unittest) unittest
1108 {
1109 	enum En { one, two }
1110 	assert(En.one.toJson() == `"one"`);
1111 	struct S { int i1, i2; S[] arr1, arr2; string[string] dic; En en; mixin NonSerialized!(i2, arr2); }
1112 	S s = S(42, 5, [S(1), S(2)], [S(3), S(4)], ["apple":"fruit", "pizza":"vegetable"], En.two);
1113 	auto s2 = jsonParse!S(toJson(s));
1114 	assert(s.i1 == s2.i1);
1115 	assert(s2.i2 is int.init);
1116 	assert(s.arr1 == s2.arr1);
1117 	assert(s2.arr2 is null);
1118 	assert(s.dic == s2.dic, s2.dic.text);
1119 	assert(s.en == En.two);
1120 }
1121 
1122 debug(ae_unittest) unittest
1123 {
1124 	alias B = Nullable!bool;
1125 	B b;
1126 
1127 	b = jsonParse!B("true");
1128 	assert(!b.isNull);
1129 	assert(b.get == true);
1130 	assert(b.toJson == "true");
1131 
1132 	b = jsonParse!B("false");
1133 	assert(!b.isNull);
1134 	assert(b.get == false);
1135 	assert(b.toJson == "false");
1136 
1137 	b = jsonParse!B("null");
1138 	assert(b.isNull);
1139 	assert(b.toJson == "null");
1140 
1141 	struct S {}
1142 	alias NS = Nullable!S;
1143 	assert(NS.init.toJson == "null");
1144 }
1145 
1146 debug(ae_unittest) unittest // Issue 49
1147 {
1148 	immutable bool b;
1149 	assert(toJson(b) == "false");
1150 }
1151 
1152 debug(ae_unittest) unittest
1153 {
1154 	import ae.utils.aa : OrderedMap;
1155 	alias M = OrderedMap!(string, int);
1156 	M m;
1157 	m["one"] = 1;
1158 	m["two"] = 2;
1159 	auto j = (cast(const)m).toJson();
1160 	assert(j == `{"one":1,"two":2}`, j);
1161 	assert(j.jsonParse!M == m);
1162 }
1163 
1164 debug(ae_unittest) unittest
1165 {
1166 	assert(string.init.toJson.jsonParse!string  is null);
1167 	assert(""         .toJson.jsonParse!string !is null);
1168 }
1169 
1170 debug(ae_unittest) unittest
1171 {
1172 	char[] s = "{}".dup;
1173 	assert(s.jsonParse!(string[string]) == null);
1174 }
1175 
1176 debug(ae_unittest) unittest
1177 {
1178 	typeof(null) n;
1179 	assert(n.toJson.jsonParse!(typeof(null)) is null);
1180 }
1181 
1182 debug(ae_unittest) unittest
1183 {
1184 	double f = 1.5;
1185 	assert(f.toJson() == "1.5");
1186 }
1187 
1188 debug(ae_unittest) unittest
1189 {
1190 	dchar c = '😸';
1191 	assert(c.toJson() == `"😸"`);
1192 }
1193 
1194 /// `fromJSON` / `toJSON` can be added to a type to control their serialized representation.
1195 debug(ae_unittest) unittest
1196 {
1197 	static struct S
1198 	{
1199 		string value;
1200 		static S fromJSON(string value) { return S(value); }
1201 		string toJSON() { return value; }
1202 	}
1203 	auto s = S("test");
1204 	assert(s.toJson == `"test"`);
1205 	assert(s.toJson.jsonParse!S == s);
1206 }
1207 
1208 debug(ae_unittest) unittest
1209 {
1210 	static struct S
1211 	{
1212 		string value;
1213 		static S fromJSON(string value) { return S(value); }
1214 		void toJSON(F)(F f) { f(value); }
1215 	}
1216 	auto s = S("test");
1217 	auto p = &s;
1218 	assert(p.toJson == `"test"`);
1219 	assert(*p.toJson.jsonParse!(S*) == s);
1220 }
1221 
1222 /// `fromJSON` / `toJSON` can also accept/return a `JSONFragment`,
1223 /// which allows full control over JSON serialization.
1224 debug(ae_unittest) unittest
1225 {
1226 	static struct BigInt
1227 	{
1228 		string decimalDigits;
1229 		static BigInt fromJSON(JSONFragment value) { return BigInt(value.json); }
1230 		JSONFragment toJSON() { return JSONFragment(decimalDigits); }
1231 	}
1232 	auto n = BigInt("12345678901234567890");
1233 	assert(n.toJson == `12345678901234567890`);
1234 	assert(n.toJson.jsonParse!BigInt == n);
1235 }
1236 
1237 // ************************************************************************
1238 
1239 /// User-defined attribute - specify name for JSON object field.
1240 /// Useful when a JSON object may contain fields, the name of which are not valid D identifiers.
1241 struct JSONName { string name; /***/ }
1242 
1243 private template getJsonName(S, string FIELD)
1244 {
1245 	static if (hasAttribute!(JSONName, __traits(getMember, S, FIELD)))
1246 		enum getJsonName = getAttribute!(JSONName, __traits(getMember, S, FIELD)).name;
1247 	else
1248 		enum getJsonName = FIELD;
1249 }
1250 
1251 // ************************************************************************
1252 
1253 /// User-defined attribute - only serialize this field if its value is different from its .init value.
1254 struct JSONOptional {}
1255 
1256 debug(ae_unittest) unittest
1257 {
1258 	static struct S { @JSONOptional bool a=true, b=false; }
1259 	assert(S().toJson == `{}`, S().toJson);
1260 	assert(S(false, true).toJson == `{"a":false,"b":true}`);
1261 }
1262 
1263 debug(ae_unittest) unittest
1264 {
1265 	static struct S { @JSONOptional float f; }
1266 	assert(S().toJson == `{}`, S().toJson);
1267 }
1268 
1269 debug(ae_unittest) unittest
1270 {
1271 	static struct S { @JSONOptional int[1] a; }
1272 	assert(S().toJson == `{}`, S().toJson);
1273 }
1274 
1275 // ************************************************************************
1276 
1277 /// User-defined attribute - skip unknown fields when deserializing.
1278 struct JSONPartial {}
1279 
1280 debug(ae_unittest) unittest
1281 {
1282 	@JSONPartial static struct S { int b; }
1283 	assert(`{"a":1,"b":2,"c":3.4,"d":[5,"x"],"de":[],"e":{"k":"v"},"ee":{},"f":true,"g":false,"h":null}`.jsonParse!S == S(2));
1284 }
1285 
1286 // ************************************************************************
1287 
1288 /// Fragment of raw JSON.
1289 /// When serialized, the .json field is inserted into the resulting
1290 /// string verbatim, without any validation.
1291 /// When deserialized, will contain the raw JSON of one JSON object of
1292 /// any type.
1293 struct JSONFragment
1294 {
1295 	string json; ///
1296 	bool opCast(T)() const if (is(T==bool)) { return !!json; } ///
1297 }
1298 
1299 debug(ae_unittest) unittest
1300 {
1301 	JSONFragment[] arr = [JSONFragment(`1`), JSONFragment(`true`), JSONFragment(`"foo"`), JSONFragment(`[55]`)];
1302 	assert(arr.toJson == `[1,true,"foo",[55]]`);
1303 	assert(arr.toJson.jsonParse!(JSONFragment[]) == arr);
1304 }