1 module mutils.serializer.json;
2 
3 import std.experimental.allocator;
4 import std.experimental.allocator.mallocator;
5 import std.meta;
6 
7 import mutils.container.vector;
8 public import mutils.serializer.common;
9 import mutils.serializer.lexer_utils;
10 import mutils.serializer.lua_json_token;
11 
12 //  COS==ContainerOrSlice
13 
14 /**
15  * Serializer to save data in json format
16  * If serialized data have to be allocated it is not saved/loaded unless it has "malloc" UDA (@("malloc"))
17  */
18 final class JSONSerializer {
19 	alias SliceElementType = char;
20 	JSONLexer lex;
21 	__gshared static JSONSerializerToken tokenSerializer = new JSONSerializerToken();
22 
23 	int beginObject(Load load, COS)(ref COS con) {
24 		static if (load == Load.yes) {
25 			assert(con[0] == '{');
26 			con ~= con[1 .. $];
27 		} else {
28 			con ~= '{';
29 		}
30 		return 0; // Just to satisfy interface
31 	}
32 
33 	void endObject(Load load, COS)(ref COS con, int begin) {
34 		static if (load == Load.yes) {
35 			assert(con[0] == '}');
36 			con ~= con[1 .. $];
37 		} else {
38 			con ~= '}';
39 		}
40 	}
41 
42 	/**
43 	 * Function loads and saves data depending on compile time variable load
44 	 * If useMalloc is true pointers, arrays, classes will be saved and loaded using Mallocator
45 	 * T is the serialized variable
46 	 * COS is char[] when load==Load.yes 
47 	 * COS container supplied by user in which data is stored when load==Load.no(save) 
48 	 */
49 	void serialize(Load load, bool useMalloc = false, T, COS)(ref T var, ref COS con) {
50 		try {
51 			static if (load == Load.yes) {
52 				lex = JSONLexer(cast(string) con, true, true);
53 				auto tokens = lex.tokenizeAll();
54 				//load
55 				tokenSerializer.serialize!(Load.yes, useMalloc)(var, tokens[]);
56 				tokens.clear();
57 			} else {
58 				//__gshared static JSONSerializerToken serializer= new JSONSerializerToken();
59 				TokenDataVector tokens;
60 				tokenSerializer.serialize!(Load.no, useMalloc)(var, tokens);
61 				tokensToCharVectorPreatyPrint!(JSONLexer)(tokens[], con);
62 				tokens.clear();
63 			}
64 		}
65 		catch (Exception e) {
66 		}
67 	}
68 
69 	//support for rvalues during load
70 	void serialize(Load load, bool useMalloc = false, T, COS)(ref T var, COS con) {
71 		static assert(load == Load.yes);
72 		serialize!(load, useMalloc)(var, con);
73 	}
74 
75 	__gshared static JSONSerializer instance = new JSONSerializer();
76 
77 }
78 
79 //-----------------------------------------
80 //--- Tests
81 //-----------------------------------------
82 
83 // Helper to avoid GC
84 private T[n] s(T, size_t n)(auto ref T[n] array) pure nothrow @nogc @safe {
85 	return array;
86 }
87 
88 // test formating
89 unittest {
90 
91 	static struct TestStruct {
92 		int a;
93 		int b;
94 		@("malloc") string c;
95 	}
96 
97 	TestStruct test;
98 	Vector!char container;
99 	string str = `
100 	
101 {
102     "b"   :145    ,  "a":  1,   "c"               :   
103 
104 
105 "asdasdas asdasdas asdasd asd"
106 }
107 `;
108 
109 	//load
110 	__gshared static JSONSerializer serializer = new JSONSerializer();
111 	serializer.serialize!(Load.yes)(test, cast(char[]) str);
112 	assert(test.a == 1);
113 	assert(test.b == 145);
114 	assert(test.c == "asdasdas asdasdas asdasd asd");
115 }
116 
117 // test formating
118 unittest {
119 	static struct TestStructB {
120 		int a;
121 	}
122 
123 	static struct TestStruct {
124 		int a;
125 		int b;
126 		TestStructB bbb;
127 	}
128 
129 	TestStruct test;
130 	Vector!char container;
131 	string str = `
132 	
133 {
134     "b"   :145,
135 	"a":{},
136 	"xxxxx":{},
137 	"bbb":13,
138 	"www":{}
139 }
140 `;
141 
142 	//load
143 	__gshared static JSONSerializer serializer = new JSONSerializer();
144 	serializer.serialize!(Load.yes)(test, cast(char[]) str);
145 
146 	assert(test.a == 0);
147 	assert(test.b == 145);
148 }
149 
150 // test basic types
151 unittest {
152 	static struct TestStructA {
153 		int a;
154 		@("malloc") string b;
155 		int c;
156 	}
157 
158 	static struct TestStruct {
159 		int a;
160 		TestStructA aa;
161 		int b;
162 		@("malloc") string c;
163 	}
164 
165 	TestStruct test;
166 	test.a = 1;
167 	test.b = 2;
168 	test.c = "asdasdasda asd asda";
169 	test.aa.a = 11;
170 	test.aa.c = 22;
171 	test.aa.b = "xxxxx";
172 	Vector!char container;
173 
174 	//save
175 	JSONSerializer.instance.serialize!(Load.no)(test, container);
176 	//writeln(container[]);
177 
178 	//reset var
179 	test = TestStruct.init;
180 
181 	//load
182 	JSONSerializer.instance.serialize!(Load.yes)(test, container[]);
183 	assert(test.a == 1);
184 	assert(test.b == 2);
185 	assert(test.c == "asdasdasda asd asda");
186 	assert(test.aa.a == 11);
187 	assert(test.aa.c == 22);
188 	assert(test.aa.b == "xxxxx");
189 }
190 
191 // test arrays
192 unittest {
193 	static struct TestStructB {
194 		@("malloc") string a = "ala";
195 	}
196 
197 	static struct TestStruct {
198 		int[3] a;
199 		@("malloc") int[] b;
200 		Vector!int c;
201 		Vector!TestStructB d;
202 		float e;
203 	}
204 
205 	TestStruct test;
206 	test.a = [1, 2, 3].s;
207 	test.b = [11, 22, 33].s;
208 	test.c ~= [1, 2, 3, 4, 5, 6, 7].s;
209 	test.d ~= [TestStructB("asddd"), TestStructB("asd12dd"), TestStructB("asddaszdd")].s;
210 	test.e = 32.52f;
211 	Vector!char container;
212 
213 	//save
214 	JSONSerializer.instance.serialize!(Load.no)(test, container);
215 
216 	//reset var
217 	test = TestStruct.init;
218 
219 	//load
220 	JSONSerializer.instance.serialize!(Load.yes)(test, container[]);
221 	//writeln(test);
222 	assert(test.a == [1, 2, 3].s);
223 	assert(test.b == [11, 22, 33].s);
224 	assert(test.c[] == [1, 2, 3, 4, 5, 6, 7].s);
225 }
226 
227 // test map
228 unittest {
229 	import mutils.container.hash_map;
230 
231 	static struct TestInner {
232 		int a;
233 		ubyte b;
234 	}
235 
236 	static struct Test {
237 		HashMap!(Vector!(char), TestInner) map;
238 		HashMap!(int, int) mapInt;
239 	}
240 
241 	Vector!char key1;
242 	Vector!char key2;
243 	key1 ~= cast(char[]) "aaaaaaAA";
244 	key2 ~= cast(char[]) "BBBBbbbb";
245 
246 	Test test;
247 	test.map.add(key1, TestInner(1, 2));
248 	test.map.add(key2, TestInner(3, 5));
249 	test.mapInt.add(100, 10);
250 	test.mapInt.add(200, 20);
251 	Vector!char container;
252 
253 	//save
254 	JSONSerializer.instance.serialize!(Load.no)(test, container);
255 
256 	//reset var
257 	test = test.init;
258 
259 	//load
260 	JSONSerializer.instance.serialize!(Load.yes)(test, container[]);
261 
262 	assert(test.map.get(key1) == TestInner(1, 2));
263 	assert(test.map.get(key2) == TestInner(3, 5));
264 	assert(test.mapInt.get(100) == 10);
265 	assert(test.mapInt.get(200) == 20);
266 }
267 
268 // test customSerialize
269 unittest {
270 
271 	static struct TestStructA {
272 		int a;
273 		int b;
274 		int c;
275 
276 		void customSerialize(Load load, Serializer, COS)(Serializer serializer, ref COS con) {
277 			auto begin = serializer.beginObject!(load)(con);
278 			scope (exit)
279 				serializer.endObject!(load)(con, begin);
280 
281 			serializer.serializeWithName!(load, "vvvA", false)(a, con);
282 			serializer.serializeWithName!(load, "vvvB", false)(b, con);
283 			serializer.serializeWithName!(load, "vvvC", false)(c, con);
284 
285 		}
286 	}
287 
288 	static struct TestStruct {
289 		int a;
290 		TestStructA innerA;
291 		int b;
292 		int c;
293 
294 		void customSerialize(Load load, Serializer, COS)(Serializer serializer, ref COS con) {
295 			auto begin = serializer.beginObject!(load)(con);
296 			scope (exit)
297 				serializer.endObject!(load)(con, begin);
298 
299 			serializer.serializeWithName!(load, "someVarA", false)(a, con);
300 			serializer.serializeWithName!(load, "someInner", false)(innerA, con);
301 			serializer.serializeWithName!(load, "someVarB", false)(b, con);
302 			serializer.serializeWithName!(load, "someVarC", false)(c, con);
303 
304 		}
305 	}
306 
307 	TestStruct test = TestStruct(1, TestStructA(10, 20, 30), 2, 3);
308 	Vector!char container;
309 	//save
310 	JSONSerializer.instance.serialize!(Load.no)(test, container);
311 	//reset var
312 	test = test.init;
313 	//load
314 	JSONSerializer.instance.serialize!(Load.yes)(test, container[]);
315 
316 	assert(test.a == 1);
317 	assert(test.innerA.a == 10);
318 	assert(test.innerA.b == 20);
319 	assert(test.innerA.c == 30);
320 	assert(test.b == 2);
321 	assert(test.c == 3);
322 
323 	string testJson = `{
324     "someVarB":2,
325     "someInner":{
326         "vvvC":30,
327         "vvvA":10,
328         "vvvB":20
329         
330     },
331     "someVarC":3,
332     "someVarA":55,
333     
334 }`;
335 
336 	//load
337 	JSONSerializer.instance.serialize!(Load.yes)(test, testJson);
338 
339 	assert(test.a == 55);
340 	assert(test.innerA.a == 10);
341 	assert(test.innerA.b == 20);
342 	assert(test.innerA.c == 30);
343 	assert(test.b == 2);
344 	assert(test.c == 3);
345 
346 }
347 
348 // test class
349 unittest {
350 	static class TestClass {
351 		int a;
352 		ubyte b;
353 	}
354 
355 	__gshared static TestClass test = new TestClass;
356 	test.a = 11;
357 	test.b = 'b';
358 	Vector!char container;
359 
360 	//save
361 	JSONSerializer.instance.serialize!(Load.no, true)(test, container);
362 
363 	//reset var
364 	test = null;
365 
366 	//load
367 	JSONSerializer.instance.serialize!(Load.yes, true)(test, container[]);
368 	assert(test.a == 11);
369 	assert(test.b == 'b');
370 }
371 
372 // test float
373 unittest {
374 	static struct TestStruct {
375 		float numA;
376 		float numB;
377 	}
378 
379 	Vector!char container;
380 	TestStruct test = TestStruct(1.11, 200);
381 
382 	//save
383 	JSONSerializer.instance.serialize!(Load.no)(test, container);
384 
385 	//reset var
386 	test = TestStruct.init;
387 	//load
388 	JSONSerializer.instance.serialize!(Load.yes)(test, container[]);
389 	assert(test.numA >= 1.1 && test.numA <= 1.2);
390 	assert(test.numB == 200);
391 }
392 // test nothing
393 unittest {
394 	static struct TestStruct {
395 	}
396 
397 	__gshared static TestStruct test;
398 	Vector!char container;
399 
400 	//save
401 	JSONSerializer.instance.serialize!(Load.no, true)(test, container);
402 	//load
403 	JSONSerializer.instance.serialize!(Load.yes, true)(test, container[]);
404 }
405 // test bools as nums
406 unittest {
407 
408 	static struct TestStruct {
409 		bool a;
410 		bool b;
411 	}
412 
413 	TestStruct test;
414 	string str = `{"a":123,"b":0}`;
415 	test.a = false;
416 	test.b = true;
417 	JSONSerializer.instance.serialize!(Load.yes)(test, cast(char[]) str);
418 	assert(test.a == true);
419 	assert(test.b == false);
420 }
421 
422 //-----------------------------------------
423 //--- Lexer 
424 //-----------------------------------------
425 
426 struct JSONLexer {
427 	enum Token {
428 		notoken = StandardTokens.notoken,
429 		white = StandardTokens.white,
430 		character = StandardTokens.character,
431 		identifier = StandardTokens.identifier,
432 		string_ = StandardTokens.string_,
433 		double_ = StandardTokens.double_,
434 		long_ = StandardTokens.long_,
435 	}
436 
437 	alias characterTokens = AliasSeq!('[', ']', '{', '}', '(', ')', ',', ':');
438 
439 	string code;
440 	string slice;
441 	bool skipUnnecessaryWhiteTokens = true;
442 
443 	uint line;
444 	uint column;
445 
446 	//@disable this();
447 
448 	this(string code, bool skipWhite, bool skipComments) {
449 		this.code = code;
450 		slice = this.code[];
451 		skipUnnecessaryWhiteTokens = skipWhite;
452 	}
453 
454 	void clear() {
455 		code = null;
456 		line = column = 0;
457 		slice = null;
458 	}
459 
460 	TokenData checkNextToken() {
461 		auto sliceCopy = slice;
462 		auto token = getNextToken();
463 		slice = sliceCopy;
464 		return token;
465 	}
466 
467 	private TokenData getNextTokenImpl() {
468 		TokenData token;
469 		switch (slice[0]) {
470 			//------- character tokens ------------------------
471 			foreach (ch; characterTokens) {
472 		case ch:
473 			}
474 			token = slice[0];
475 			slice = slice[1 .. $];
476 			return token;
477 
478 			//--------- white tokens --------------------------
479 			foreach (ch; whiteTokens) {
480 		case ch:
481 			}
482 			serializeWhiteTokens!(true)(token, slice);
483 			return token;
484 
485 			//------- escaped strings -------------------------
486 		case '"':
487 			serializeStringToken!(true)(token, slice);
488 			return token;
489 
490 			//------- something else -------------------------
491 		default:
492 			break;
493 		}
494 		if (isIdentifierFirstChar(slice[0])) {
495 			serializeIdentifier!(true)(token, slice);
496 		} else if ((slice[0] >= '0' && slice[0] <= '9') || slice[0] == '-') {
497 			serializeNumberToken!(true)(token, slice);
498 		} else {
499 			slice = null;
500 		}
501 		return token;
502 
503 	}
504 
505 	TokenData getNextToken() {
506 		TokenData token;
507 		string sliceCopy = slice[];
508 		scope (exit) {
509 			token.line = line;
510 			token.column = column;
511 			updateLineAndCol(line, column, sliceCopy, slice);
512 		}
513 		while (slice.length > 0) {
514 			token = getNextTokenImpl();
515 			if (skipUnnecessaryWhiteTokens && token.type == Token.white) {
516 				token = TokenData.init;
517 				continue;
518 			}
519 			break;
520 		}
521 		return token;
522 	}
523 
524 	static void toChars(Vec)(TokenData token, ref Vec vec) {
525 		final switch (cast(Token) token.type) {
526 		case Token.long_:
527 		case Token.double_:
528 			serializeNumberToken!(false)(token, vec);
529 			break;
530 		case Token.character:
531 			vec ~= token.ch;
532 			break;
533 		case Token.white:
534 		case Token.identifier:
535 			vec ~= cast(char[]) token.str;
536 			break;
537 		case Token.string_:
538 			vec ~= '"';
539 			vec ~= cast(char[]) token.getEscapedString();
540 			vec ~= '"';
541 			break;
542 
543 		case Token.notoken:
544 			assert(0);
545 		}
546 
547 	}
548 
549 }
550 
551 unittest {
552 	string code = `{ [ ala: "asdasd", ccc:123.3f]}"`;
553 	JSONLexer json = JSONLexer(code, true, true);
554 	TokenData token;
555 	token.type = StandardTokens.identifier;
556 	token.str = "asd";
557 }
558 
559 unittest {
560 	void testOutputTheSame(string str) {
561 		string sliceCopy = str;
562 		JSONLexer json = JSONLexer(str, false, false);
563 		Vector!TokenData tokens = json.tokenizeAll();
564 
565 		JSONLexer json2 = JSONLexer(null, false, false);
566 		//writeln(tokens[]);
567 		//writeln(json2.tokensToString(tokens[0..$-1]),"|\n\n\n",sliceCopy,"|");
568 		assert(json2.tokensToString(tokens[0 .. $ - 1])[] == cast(char[]) sliceCopy);
569 
570 	}
571 
572 	testOutputTheSame("  12345 ");
573 	testOutputTheSame(`{ [ ala :  "asdasd",
574 	 ccc: 
575 123]  }  `);
576 }
577 
578 alias JSONSerializerToken = JSON_Lua_SerializerToken!(true);
579 
580 //-----------------------------------------
581 //--- Tests
582 //-----------------------------------------
583 
584 // test formating
585 unittest {
586 	string str = ` 12345 `;
587 	int a;
588 	JSONLexer lex = JSONLexer(cast(string) str, true, true);
589 	auto tokens = lex.tokenizeAll();
590 
591 	//load
592 	__gshared static JSONSerializerToken serializer = new JSONSerializerToken();
593 	serializer.serialize!(Load.yes)(a, tokens[]);
594 	assert(a == 12345);
595 
596 	tokens.clear();
597 	serializer.serialize!(Load.no)(a, tokens);
598 	assert(tokens[0].type == StandardTokens.long_);
599 	assert(tokens[0].long_ == 12345);
600 
601 }
602 
603 unittest {
604 	string str = `
605 	
606 {
607 "wwwww":{"w":[1,2,3]},
608     "b"   :145    ,  "a":  1,   "c"               :   
609 
610 
611 "asdasdas asdasdas asdasd asd"
612 }
613 `;
614 	static struct TestStruct {
615 		int a;
616 		int b;
617 		@("malloc") string c;
618 	}
619 
620 	TestStruct test;
621 	JSONLexer lex = JSONLexer(cast(string) str, true, true);
622 	auto tokens = lex.tokenizeAll();
623 
624 	//load
625 	__gshared static JSONSerializerToken serializer = new JSONSerializerToken();
626 	auto ttt = tokens[];
627 	serializer.serialize!(Load.yes)(test, ttt);
628 	assert(test.a == 1);
629 	assert(test.b == 145);
630 	assert(test.c == "asdasdas asdasdas asdasd asd");
631 
632 	tokens.clear();
633 
634 	serializer.serialize!(Load.no)(test, tokens);
635 
636 	assert(tokens.length == 13);
637 }
638 
639 // Test escaping
640 unittest {
641 	string str = `
642 {
643   "json":"{\n     \"lineData\":[\n                {\"time\":0.0, \"setCamPos\": true},\n                {\"time\":1.0    , \"triggerEvent\":  \"gendialog0.json\", \"setCamPos\": true},\n     ],\n    \n}",
644 
645 }
646 `;
647 	static struct TestStruct {
648 		@("malloc") string json;
649 	}
650 
651 	TestStruct test;
652 	JSONLexer lex = JSONLexer(cast(string) str, true, true);
653 	auto tokens = lex.tokenizeAll();
654 
655 	//load
656 	__gshared static JSONSerializerToken serializer = new JSONSerializerToken();
657 	auto ttt = tokens[];
658 	assert(tokens.length == 7);
659 }
660 
661 
662 // test formating
663 unittest {
664 	static struct TestStructB {
665 		int a;
666 	}
667 
668 	static struct TestStruct {
669 		int a;
670 		int b;
671 		TestStructB bbb;
672 	}
673 
674 	TestStruct test;
675 	//Vector!char container;
676 	string str = `
677  
678  {
679  "b"   :145,
680  "a":{},
681  "xxxxx":{},
682  "bbb":13,
683  "www":{}
684 
685  `;
686 
687 	JSONLexer lex = JSONLexer(cast(string) str, true, true);
688 	auto tokens = lex.tokenizeAll();
689 	//load
690 	__gshared static JSONSerializerToken serializer = new JSONSerializerToken();
691 	serializer.serialize!(Load.yes)(test, tokens[]);
692 
693 	assert(test.a == 0);
694 	assert(test.b == 145);
695 }
696 
697 // test basic types
698 unittest {
699 	static struct TestStructA {
700 		int a;
701 		@("malloc") string b;
702 		int c;
703 	}
704 
705 	static struct TestStruct {
706 		int a;
707 		TestStructA aa;
708 		int b;
709 		@("malloc") string c;
710 	}
711 
712 	TestStruct test;
713 	test.a = 1;
714 	test.b = 2;
715 	test.c = "asdasdasda asd asda";
716 	test.aa.a = 11;
717 	test.aa.c = 22;
718 	test.aa.b = "xxxxx";
719 	Vector!TokenData tokens;
720 
721 	//save
722 	__gshared static JSONSerializerToken serializer = new JSONSerializerToken();
723 	serializer.serialize!(Load.no)(test, tokens);
724 
725 	//reset var
726 	test = TestStruct.init;
727 
728 	//load
729 	serializer.serialize!(Load.yes)(test, tokens[]);
730 	assert(test.a == 1);
731 	assert(test.b == 2);
732 	assert(test.c == "asdasdasda asd asda");
733 	assert(test.aa.a == 11);
734 	assert(test.aa.c == 22);
735 	assert(test.aa.b == "xxxxx");
736 }
737 
738 // test arrays
739 unittest {
740 	static struct TestStructB {
741 		@("malloc") string a = "ala";
742 	}
743 
744 	static struct TestStruct {
745 		int[3] a;
746 		@("malloc") int[] b;
747 		Vector!int c;
748 		Vector!TestStructB d;
749 		float e;
750 	}
751 
752 	TestStruct test;
753 	test.a = [1, 2, 3].s;
754 	test.b = [11, 22, 33].s;
755 	test.c ~= [1, 2, 3, 4, 5, 6, 7].s;
756 	test.d ~= [TestStructB("asddd"), TestStructB("asd12dd"), TestStructB("asddaszdd")].s;
757 	test.e = 32.52f;
758 	//Vector!char container;
759 	Vector!TokenData tokens;
760 
761 	//save
762 	JSONSerializerToken.instance.serialize!(Load.no)(test, tokens);
763 
764 	//reset var
765 	test = TestStruct.init;
766 
767 	//load
768 	JSONSerializerToken.instance.serialize!(Load.yes)(test, tokens[]);
769 	assert(test.a == [1, 2, 3].s);
770 	assert(test.b == [11, 22, 33].s);
771 	assert(test.c[] == [1, 2, 3, 4, 5, 6, 7].s);
772 }
773 
774 // test class
775 unittest {
776 	static class TestClass {
777 		int a;
778 		ubyte b;
779 	}
780 
781 	__gshared static TestClass test = new TestClass;
782 	test.a = 11;
783 	test.b = 'b';
784 	Vector!TokenData tokens;
785 
786 	//save
787 	JSONSerializerToken.instance.serialize!(Load.no, true)(test, tokens);
788 	//reset var
789 	test = null;
790 
791 	//load
792 	JSONSerializerToken.instance.serialize!(Load.yes, true)(test, tokens[]);
793 
794 	assert(test.a == 11);
795 	assert(test.b == 'b');
796 }
797 
798 // test bool
799 unittest {
800 
801 	static struct TestStruct {
802 		bool a;
803 		bool b;
804 	}
805 
806 	TestStruct test;
807 	test.a = true;
808 	test.b = false;
809 
810 	Vector!TokenData tokens;
811 	//save
812 	JSONSerializerToken.instance.serialize!(Load.no)(test, tokens);
813 	//{a=true,b=false}
814 	assert(tokens[3].type == StandardTokens.identifier);
815 	assert(tokens[7].type == StandardTokens.identifier);
816 	test.a = false;
817 	test.b = true;
818 	//load
819 	JSONSerializerToken.instance.serialize!(Load.yes)(test, tokens[]);
820 	assert(test.a == true);
821 	assert(test.b == false);
822 }