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 }