1 module mutils.serializer.json;
2 
3 import std.meta;
4 
5 public import mutils.serializer.common;
6 
7 import mutils.serializer.lexer_utils;
8 
9 
10 /**
11  * Serializer to save data in json format
12  * If serialized data have to be allocated it is not saved/loaded unless it has "malloc" UDA (@("malloc"))
13  */
14 class JSONSerializer{
15 	/**
16 	 * Function loads and saves data depending on compile time variable load
17 	 * If useMalloc is true pointers, arrays, classes will be saved and loaded using Mallocator
18 	 * T is the serialized variable
19 	 * ContainerOrSlice is char[] when load==Load.yes 
20 	 * ContainerOrSlice container supplied by user in which data is stored when load==Load.no(save) 
21 	 */
22 	void serialize(Load load,bool useMalloc=false, T, ContainerOrSlice)(ref T var,ref ContainerOrSlice con){
23 		try{
24 			static if(load==Load.yes){
25 				JSONLexer lex=JSONLexer(cast(string)con, true, true);
26 				auto tokens=lex.tokenizeAll();				
27 				//load
28 				__gshared static JSONSerializerToken serializer= new JSONSerializerToken();
29 				serializer.serialize!(Load.yes, useMalloc)(var,tokens[]);		
30 				tokens.clear();
31 			}else{
32 				__gshared static JSONSerializerToken serializer= new JSONSerializerToken();
33 				TokenDataVector tokens;
34 				serializer.serialize!(Load.no, useMalloc)(var,tokens);
35 				tokensToCharVectorPreatyPrint!(JSONLexer)(tokens[],con);
36 				tokens.clear();
37 			}
38 		}catch(Exception e){}
39 	}
40 
41 	//support for rvalues during load
42 	void serialize(Load load,bool useMalloc=false, T, ContainerOrSlice)(ref T var,ContainerOrSlice con){
43 		static assert(load==Load.yes);
44 		serialize!(load,useMalloc)(var,con);		
45 	}
46 
47 	__gshared static JSONSerializer instance= new JSONSerializer();
48 
49 }
50 
51 
52 //-----------------------------------------
53 //--- Tests
54 //-----------------------------------------
55 import mutils.container.vector;
56 // test formating
57 unittest{
58 	
59 	static struct TestStruct{
60 		int a;
61 		int b;
62 		@("malloc") string c;
63 	}
64 	TestStruct test;
65 	Vector!char container;
66 	string str=`
67 	
68 {
69     "b"   :145    ,  "a":  1,   "c"               :   
70 
71 
72 "asdasdas asdasdas asdasd asd"
73 }
74 `;
75 	
76 	
77 	//load
78 	__gshared static JSONSerializer serializer= new JSONSerializer();
79 	serializer.serialize!(Load.yes)(test,cast(char[])str);
80 	//writeln(test);
81 	assert(test.a==1);
82 	assert(test.b==145);
83 	assert(test.c=="asdasdas asdasdas asdasd asd");
84 }
85 
86 // test formating
87 unittest{
88 	static struct TestStructB{
89 		int a;
90 	}
91 	static struct TestStruct{
92 		int a;
93 		int b;
94 		TestStructB bbb;
95 	}
96 	TestStruct test;
97 	Vector!char container;
98 	string str=`
99 	
100 {
101     "b"   :145,
102 	"a":{},
103 	"xxxxx":{},
104 	"bbb":13,
105 	"www":{}
106 
107 `;
108 	
109 	//load
110 	__gshared static JSONSerializer serializer= new JSONSerializer();
111 	serializer.serialize!(Load.yes)(test,cast(char[])str);
112 	
113 	assert(test.a==0);
114 	assert(test.b==145);
115 }
116 
117 // test basic types
118 unittest{
119 	static struct TestStructA{
120 		int a;
121 		@("malloc") string b;
122 		int c;
123 	}
124 	static struct TestStruct{
125 		int a;
126 		TestStructA aa;
127 		int b;
128 		@("malloc") string c;
129 	}
130 	TestStruct test;
131 	test.a=1;
132 	test.b=2;
133 	test.c="asdasdasda asd asda";
134 	test.aa.a=11;
135 	test.aa.c=22;
136 	test.aa.b="xxxxx";
137 	Vector!char container;
138 	
139 	//save
140 	__gshared static JSONSerializer serializer= new JSONSerializer();
141 	serializer.serialize!(Load.no)(test,container);
142 	//writeln(container[]);
143 	
144 	//reset var
145 	test=TestStruct.init;
146 	
147 	//load
148 	serializer.serialize!(Load.yes)(test,container[]);
149 	assert(test.a==1);
150 	assert(test.b==2);
151 	assert(test.c=="asdasdasda asd asda");
152 	assert(test.aa.a==11);
153 	assert(test.aa.c==22);
154 	assert(test.aa.b=="xxxxx");
155 }
156 
157 // test arrays
158 unittest{
159 	static struct TestStructB{
160 		@("malloc") string a="ala";
161 	}
162 	static struct TestStruct{
163 		int[3] a;
164 		@("malloc") int[] b;
165 		Vector!int c;
166 		Vector!TestStructB d;
167 		float e;
168 	}
169 	TestStruct test;
170 	test.a=[1,2,3];
171 	test.b=[11,22,33];
172 	test.c~=[1,2,3,4,5,6,7];
173 	test.d~=[TestStructB("asddd"),TestStructB("asd12dd"),TestStructB("asddaszdd")];
174 	test.e=32.52f;
175 	Vector!char container;
176 	
177 	//save
178 	__gshared static JSONSerializer serializer= new JSONSerializer();
179 	serializer.serialize!(Load.no)(test,container);
180 	
181 	//reset var
182 	test=TestStruct.init;
183 	
184 	//load
185 	serializer.serialize!(Load.yes)(test,container[]);
186 	//writeln(test);
187 	assert(test.a==[1,2,3]);
188 	assert(test.b==[11,22,33]);
189 	assert(test.c[]==[1,2,3,4,5,6,7]);
190 }
191 
192 // test map
193 unittest{
194 	import mutils.container.hash_map;
195 	import mutils.container.hash_set;
196 	static struct TestInner{
197 		int a;
198 		ubyte b;
199 	}
200 
201 	static struct Test{
202 		HashMap!(Vector!char, TestInner) map;
203 		HashMap!(int, int) mapInt;
204 	}
205 
206 	Vector!char key1;
207 	Vector!char key2;
208 	key1~=cast(char[])"aaaaaaAA";
209 	key2~=cast(char[])"BBBBbbbb";
210 
211 	Test test;
212 	test.map.add(key1, TestInner(1, 2));
213 	test.map.add(key2, TestInner(3, 5));
214 	test.mapInt.add(100, 10);
215 	test.mapInt.add(200, 20);
216 	Vector!char container;
217 	
218 	//save
219 	JSONSerializer.instance.serialize!(Load.no)(test,container);
220 
221 	//reset var
222 	test=test.init;
223 	
224 	//load
225 	JSONSerializer.instance.serialize!(Load.yes)(test,container[]);
226 	assert(test.map.get(key1)==TestInner(1, 2));
227 	assert(test.map.get(key2)==TestInner(3, 5));
228 	assert(test.mapInt.get(100)==10);
229 	assert(test.mapInt.get(200)==20);
230 }
231 
232 // test class
233 unittest{
234 	static class TestClass{
235 		int a;
236 		ubyte b;
237 	}
238 	__gshared static TestClass test=new TestClass;
239 	test.a=11;
240 	test.b='b';
241 	Vector!char container;
242 	
243 	//save
244 	__gshared static JSONSerializer serializer= new JSONSerializer();
245 	serializer.serialize!(Load.no,true)(test,container);
246 
247 	//reset var
248 	test=null;
249 
250 	//load
251 	serializer.serialize!(Load.yes,true)(test,container[]);
252 	assert(test.a==11);
253 	assert(test.b=='b');
254 }
255 
256 // test nothing
257 unittest{
258 	static struct TestStruct{
259 	}
260 	__gshared static TestStruct test;
261 	Vector!char container;
262 	
263 	//save
264 	JSONSerializer.instance.serialize!(Load.no,true)(test, container);
265 	//load
266 	JSONSerializer.instance.serialize!(Load.yes,true)(test,container[]);
267 }
268 
269 //-----------------------------------------
270 //--- Lexer 
271 //-----------------------------------------
272 
273 struct JSONLexer{
274 	enum Token{
275 		notoken=StandardTokens.notoken,
276 		white=StandardTokens.white,
277 		character=StandardTokens.character,
278 		identifier=StandardTokens.identifier,
279 		string_=StandardTokens.string_,
280 		double_=StandardTokens.double_,
281 		long_=StandardTokens.long_,
282 	}
283 	
284 	alias characterTokens=AliasSeq!('[',']','{','}','(',')',',',':');
285 	
286 	Vector!char code;
287 	string slice;
288 	bool skipUnnecessaryWhiteTokens=true;
289 	
290 	uint line;
291 	uint column;
292 	
293 	@disable this();
294 	
295 	this(string code, bool skipWhite, bool skipComments){
296 		this.code~=cast(char[])code;
297 		slice=cast(string)this.code[];
298 		skipUnnecessaryWhiteTokens=skipWhite;
299 	}	
300 	
301 	void clear(){
302 		code.clear();
303 		line=column=0;
304 		slice=null;
305 	}	
306 	
307 	TokenData checkNextToken(){
308 		auto sliceCopy=slice;
309 		auto token=getNextToken();
310 		slice=sliceCopy;
311 		return token;
312 	}
313 	
314 	private TokenData getNextTokenImpl(){
315 		TokenData token;
316 		switch(slice[0]){
317 			//------- character tokens ------------------------
318 			foreach(ch;characterTokens){
319 				case ch:
320 			}
321 			token=slice[0];
322 			slice=slice[1..$];
323 			return token;
324 			
325 			
326 			//--------- white tokens --------------------------
327 			foreach(ch;whiteTokens){
328 				case ch:
329 			}
330 			serializeWhiteTokens!(true)(token,slice);
331 			return token;
332 			
333 			//------- escaped strings -------------------------
334 			case '"':
335 				serializeStringToken!(true)(token,slice);
336 				return token;
337 				
338 				//------- something else -------------------------
339 			default:
340 				break;
341 		}
342 		if(isIdentifierFirstChar(slice[0])){
343 			serializeIdentifier!(true)(token,slice);
344 		}else if((slice[0]>='0' && slice[0]<='9') || slice[0]=='-'){
345 			serializeNumberToken!(true)(token,slice);
346 		}else{
347 			slice=null;
348 		}
349 		return token;
350 		
351 	}
352 	
353 	TokenData getNextToken(){
354 		TokenData token;
355 		string sliceCopy=slice[];
356 		scope(exit){
357 			token.line=line;
358 			token.column=column;
359 			updateLineAndCol(line,column,sliceCopy,slice);
360 		}
361 		while(slice.length>0){
362 			token=getNextTokenImpl();
363 			if(skipUnnecessaryWhiteTokens && token.type==Token.white){
364 				token=TokenData.init;
365 				continue;
366 			}
367 			break;
368 		}
369 		return token;
370 	}
371 	
372 	
373 	static void toChars(Vec)(TokenData token, ref Vec vec){
374 		
375 		final switch(cast(Token)token.type){
376 			case Token.long_:
377 			case Token.double_:
378 				serializeNumberToken!(false)(token,vec);
379 				break;
380 			case Token.character:
381 				vec~=token.ch;
382 				break;
383 			case Token.white:
384 			case Token.identifier:
385 				vec~=cast(char[])token.str;
386 				break;
387 			case Token.string_:
388 				vec~='"';
389 				vec~=cast(char[])token.getEscapedString();
390 				vec~='"';
391 				break;
392 				
393 			case Token.notoken:
394 				assert(0);
395 		}
396 		
397 	}
398 	
399 	
400 }
401 
402 unittest{
403 	string code=`{ [ ala: "asdasd", ccc:123.3f]}"`;
404 	JSONLexer json=JSONLexer(code,true,true);
405 	TokenData token;
406 	token.type=StandardTokens.identifier;
407 	token.str="asd";
408 }
409 
410 unittest{
411 	void testOutputTheSame(string str){
412 		string sliceCopy=str;
413 		JSONLexer json=JSONLexer(str, false,false);
414 		Vector!TokenData tokens=json.tokenizeAll();
415 		
416 		JSONLexer json2=JSONLexer([], false,false);
417 		//writeln(tokens[]);
418 		//writeln(json2.tokensToString(tokens[0..$-1]),"|\n\n\n",sliceCopy,"|");
419 		assert(json2.tokensToString(tokens[0..$-1])==sliceCopy);
420 		
421 	}
422 	testOutputTheSame("  12345 ");
423 	testOutputTheSame(`{ [ ala :  "asdasd",
424 	 ccc: 
425 123]  }  `);
426 }
427 
428 
429 import mutils.serializer.lua_json_token;
430 
431 alias JSONSerializerToken= JSON_Lua_SerializerToken!(true);
432 
433 
434 
435 //-----------------------------------------
436 //--- Tests
437 //-----------------------------------------
438 import mutils.container.vector;
439 // test formating
440 unittest{
441 	string str=` 12345 `;
442 	int a;
443 	JSONLexer lex=JSONLexer(cast(string)str,true,true);
444 	auto tokens=lex.tokenizeAll();
445 	
446 	
447 	//load
448 	__gshared static JSONSerializerToken serializer= new JSONSerializerToken();
449 	serializer.serialize!(Load.yes)(a,tokens[]);
450 	assert(a==12345);
451 	
452 	tokens.clear();
453 	serializer.serialize!(Load.no)(a,tokens);
454 	assert(tokens[0].type==StandardTokens.long_);
455 	assert(tokens[0].long_==12345);
456 	
457 	
458 }
459 
460 unittest{
461 	string str=`
462 	
463 {
464 "wwwww":{"w":[1,2,3]},
465     "b"   :145    ,  "a":  1,   "c"               :   
466 
467 
468 "asdasdas asdasdas asdasd asd"
469 }
470 `;
471 	static struct TestStruct{
472 		int a;
473 		int b;
474 		@("malloc") string c;
475 	}
476 	TestStruct test;
477 	JSONLexer lex=JSONLexer(cast(string)str,true,true);
478 	auto tokens=lex.tokenizeAll();	
479 	
480 	//load
481 	__gshared static JSONSerializerToken serializer= new JSONSerializerToken();
482 	auto ttt=tokens[];
483 	serializer.serialize!(Load.yes)(test,ttt);
484 	assert(test.a==1);
485 	assert(test.b==145);
486 	assert(test.c=="asdasdas asdasdas asdasd asd");
487 	
488 	tokens.clear();
489 	
490 	serializer.serialize!(Load.no)(test,tokens);
491 	
492 	assert(tokens.length==13);
493 }
494 
495 
496 
497 
498 
499 
500 
501 // test formating
502 unittest{
503 	static struct TestStructB{
504 		int a;
505 	}
506 	static struct TestStruct{
507 		int a;
508 		int b;
509 		TestStructB bbb;
510 	}
511 	TestStruct test;
512 	//Vector!char container;
513 	string str=`
514  
515  {
516  "b"   :145,
517  "a":{},
518  "xxxxx":{},
519  "bbb":13,
520  "www":{}
521 
522  `;
523 	
524 	JSONLexer lex=JSONLexer(cast(string)str,true,true);
525 	auto tokens=lex.tokenizeAll();	
526 	//load
527 	__gshared static JSONSerializerToken serializer= new JSONSerializerToken();
528 	serializer.serialize!(Load.yes)(test,tokens[]);
529 	
530 	assert(test.a==0);
531 	assert(test.b==145);
532 }
533 
534 
535 // test basic types
536 unittest{
537 	static struct TestStructA{
538 		int a;
539 		@("malloc") string b;
540 		int c;
541 	}
542 	static struct TestStruct{
543 		int a;
544 		TestStructA aa;
545 		int b;
546 		@("malloc") string c;
547 	}
548 	TestStruct test;
549 	test.a=1;
550 	test.b=2;
551 	test.c="asdasdasda asd asda";
552 	test.aa.a=11;
553 	test.aa.c=22;
554 	test.aa.b="xxxxx";
555 	Vector!TokenData tokens;
556 	
557 	//save
558 	__gshared static JSONSerializerToken serializer= new JSONSerializerToken();
559 	serializer.serialize!(Load.no)(test,tokens);
560 	
561 	//reset var
562 	test=TestStruct.init;
563 	
564 	//load
565 	serializer.serialize!(Load.yes)(test,tokens[]);
566 	assert(test.a==1);
567 	assert(test.b==2);
568 	assert(test.c=="asdasdasda asd asda");
569 	assert(test.aa.a==11);
570 	assert(test.aa.c==22);
571 	assert(test.aa.b=="xxxxx");
572 }
573 
574 // test arrays
575 unittest{
576 	static struct TestStructB{
577 		@("malloc") string a=cast(string)"ala";
578 	}
579 	static struct TestStruct{
580 		int[3] a;
581 		@("malloc") int[] b;
582 		Vector!int c;
583 		Vector!TestStructB d;
584 		float e;
585 	}
586 	TestStruct test;
587 	test.a=[1,2,3];
588 	test.b=[11,22,33];
589 	test.c~=[1,2,3,4,5,6,7];
590 	test.d~=[TestStructB(cast(string)"asddd"),TestStructB(cast(string)"asd12dd"),TestStructB(cast(string)"asddaszdd")];
591 	test.e=32.52f;
592 	//Vector!char container;
593 	Vector!TokenData tokens;
594 	
595 	
596 	//save
597 	__gshared static JSONSerializerToken serializer= new JSONSerializerToken();
598 	serializer.serialize!(Load.no)(test,tokens);
599 	
600 	//reset var
601 	test=TestStruct.init;
602 	
603 	//load
604 	serializer.serialize!(Load.yes)(test,tokens[]);
605 	assert(test.a==[1,2,3]);
606 	assert(test.b==[11,22,33]);
607 	assert(test.c[]==[1,2,3,4,5,6,7]);
608 }
609 
610 
611 
612 // test class
613 unittest{
614 	static class TestClass{
615 		int a;
616 		ubyte b;
617 	}
618 	__gshared static TestClass test=new TestClass;
619 	test.a=11;
620 	test.b='b';
621 	Vector!TokenData tokens;
622 	
623 	//save
624 	__gshared static JSONSerializerToken serializer= new JSONSerializerToken();
625 	serializer.serialize!(Load.no,true)(test, tokens);
626 	//reset var
627 	test=null;
628 	
629 	//load
630 	serializer.serialize!(Load.yes,true)(test,tokens[]);
631 	
632 	assert(test.a==11);
633 	assert(test.b=='b');
634 }