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 }