1 /++ 2 $(H3 ASDF and JSON Serialization) 3 4 For aggregate types the order of the (de)serialization is the folowing: 5 1. All public fields of `alias ? this` that are not hidden by members of `this` (recursively). 6 2. All public fields of `this`. 7 3. All public properties of `alias ? this` that are not hidden by members of `this` (recursively). 8 4. All public properties of `this`. 9 10 Publicly imports `mir.serde` from the `mir-algorithm` package. 11 +/ 12 module asdf.serialization; 13 14 import asdf.jsonparser: assumePure; 15 import mir.algebraic: isVariant; 16 import mir.reflection; 17 import std.range.primitives: isOutputRange; 18 public import mir.serde; 19 20 /// 21 pure 22 unittest 23 { 24 import asdf; 25 import std.bigint; 26 import std.datetime; 27 import mir.conv; 28 29 enum E : char 30 { 31 a, 32 b, 33 c, 34 } 35 36 static class C 37 { 38 private double _foo; 39 pure: 40 this() 41 { 42 _foo = 4; 43 } 44 45 double foo() const @property 46 { 47 return _foo + 10; 48 } 49 50 void foo(double d) @property 51 { 52 _foo = d - 10; 53 } 54 } 55 56 import mir.timestamp: Timestamp; 57 58 static struct S 59 { 60 static int staticNotSeialised = 5; 61 enum int enumsNotSeialised = 3; 62 63 @serdeProxy!Timestamp 64 DateTime time; 65 66 C object; 67 68 string[E] map; 69 70 @serdeKeys("bar_common", "bar") 71 string bar; 72 } 73 74 enum json = `{"time":"2016-03-04T00:00:00-00:00","object":{"foo":14.0},"map":{"a":"A"},"bar_common":"escaped chars = '\\', '\"', '\t', '\r', '\n'"}`; 75 auto value = S( 76 DateTime(2016, 3, 4), 77 new C, 78 [E.a : "A"], 79 "escaped chars = '\\', '\"', '\t', '\r', '\n'"); 80 import mir.test: should; 81 serializeToJson(cast(const)value).should == json; // check serialization of const data 82 serializeToAsdf(value).to!string.should == json; 83 deserialize!S(json).serializeToJson.should == json; 84 } 85 86 /// `finalizeSerialization` method 87 unittest 88 { 89 import asdf; 90 91 static struct S 92 { 93 string a; 94 int b; 95 96 void finalizeSerialization(Serializer)(ref Serializer serializer) 97 { 98 serializer.putKey("c"); 99 serializer.putValue(100); 100 } 101 } 102 assert(S("bar", 3).serializeToJson == `{"a":"bar","b":3,"c":100}`); 103 } 104 105 /// `finalizeDeserialization` method 106 pure unittest 107 { 108 import asdf; 109 110 static struct S 111 { 112 string a; 113 int b; 114 115 @serdeIgnoreIn 116 double sum; 117 118 void finalizeDeserialization(Asdf data) pure 119 { 120 auto r = data["c", "d"]; 121 auto a = r["e"].get(0.0); 122 auto b = r["g"].get(0.0); 123 sum = a + b; 124 } 125 126 void serdeFinalize() pure 127 { 128 sum *= 2; 129 } 130 } 131 assert(`{"a":"bar","b":3,"c":{"d":{"e":6,"g":7}}}`.deserialize!S == S("bar", 3, 26)); 132 } 133 134 /// A user may define setter and/or getter properties. 135 unittest 136 { 137 import asdf; 138 import mir.conv: to; 139 140 static struct S 141 { 142 @serdeIgnore string str; 143 pure: 144 string a() @property 145 { 146 return str; 147 } 148 149 void b(int s) @property 150 { 151 str = s.to!string; 152 } 153 } 154 155 assert(S("str").serializeToJson == `{"a":"str"}`); 156 assert(`{"b":123}`.deserialize!S.str == "123"); 157 } 158 159 /// Support for custom nullable types (types that has a bool property `isNull`, 160 /// non-void property `get` returning payload and void property `nullify` that 161 /// makes nullable type to null value) 162 unittest 163 { 164 import asdf; 165 166 static struct MyNullable 167 { 168 long value; 169 170 @property 171 isNull() const 172 { 173 return value == 0; 174 } 175 176 @property 177 get() 178 { 179 return value; 180 } 181 182 @property 183 nullify() 184 { 185 value = 0; 186 } 187 188 auto opAssign(long value) 189 { 190 this.value = value; 191 } 192 } 193 194 static struct Foo 195 { 196 MyNullable my_nullable; 197 string field; 198 199 bool opEquals()(auto ref const(typeof(this)) rhs) 200 { 201 if (my_nullable.isNull && rhs.my_nullable.isNull) 202 return field == rhs.field; 203 204 if (my_nullable.isNull != rhs.my_nullable.isNull) 205 return false; 206 207 return my_nullable == rhs.my_nullable && 208 field == rhs.field; 209 } 210 } 211 212 Foo foo; 213 foo.field = "it's a foo"; 214 215 assert (serializeToJson(foo) == `{"my_nullable":null,"field":"it's a foo"}`); 216 217 foo.my_nullable = 200; 218 219 assert (deserialize!Foo(`{"my_nullable":200,"field":"it's a foo"}`) == Foo(MyNullable(200), "it's a foo")); 220 221 import std.typecons : Nullable; 222 223 static struct Bar 224 { 225 Nullable!long nullable; 226 string field; 227 228 bool opEquals()(auto ref const(typeof(this)) rhs) 229 { 230 if (nullable.isNull && rhs.nullable.isNull) 231 return field == rhs.field; 232 233 if (nullable.isNull != rhs.nullable.isNull) 234 return false; 235 236 return nullable == rhs.nullable && 237 field == rhs.field; 238 } 239 } 240 241 Bar bar; 242 bar.field = "it's a bar"; 243 244 assert (serializeToJson(bar) == `{"nullable":null,"field":"it's a bar"}`); 245 246 bar.nullable = 777; 247 assert (deserialize!Bar(`{"nullable":777,"field":"it's a bar"}`) == Bar(Nullable!long(777), "it's a bar")); 248 249 static struct S 250 { 251 long i; 252 253 SerdeException deserializeFromAsdf(Asdf data) 254 { 255 if (auto exc = deserializeValue(data, i)) 256 return exc; 257 return null; 258 } 259 } 260 261 static struct T 262 { 263 // import std.typecons: Nullable; 264 import mir.algebraic: Nullable; 265 Nullable!S test; 266 } 267 T t = deserialize!T(`{ "test": 5 }`); 268 assert(t.test.i == 5); 269 } 270 271 272 // unittest 273 // { 274 // Asdf[string] map; 275 276 // map["num"] = serializeToAsdf(124); 277 // map["str"] = serializeToAsdf("value"); 278 279 // import std.stdio; 280 // map.serializeToJson.writeln(); 281 // } 282 283 /// Support for floating point nan and (partial) infinity 284 unittest 285 { 286 import mir.conv: to; 287 import asdf; 288 289 static struct Foo 290 { 291 float f; 292 293 bool opEquals()(auto ref const(typeof(this)) rhs) 294 { 295 import std.math : isNaN, approxEqual; 296 297 if (f.isNaN && rhs.f.isNaN) 298 return true; 299 300 return approxEqual(f, rhs.f); 301 } 302 } 303 304 // test for Not a Number 305 assert (serializeToJson(Foo()).to!string == `{"f":"nan"}`); 306 assert (serializeToAsdf(Foo()).to!string == `{"f":"nan"}`); 307 308 assert (deserialize!Foo(`{"f":null}`) == Foo()); 309 assert (deserialize!Foo(`{"f":"nan"}`) == Foo()); 310 311 assert (serializeToJson(Foo(1f/0f)).to!string == `{"f":"inf"}`); 312 assert (serializeToAsdf(Foo(1f/0f)).to!string == `{"f":"inf"}`); 313 assert (deserialize!Foo(`{"f":"inf"}`) == Foo( float.infinity)); 314 assert (deserialize!Foo(`{"f":"-inf"}`) == Foo(-float.infinity)); 315 316 assert (serializeToJson(Foo(-1f/0f)).to!string == `{"f":"-inf"}`); 317 assert (serializeToAsdf(Foo(-1f/0f)).to!string == `{"f":"-inf"}`); 318 assert (deserialize!Foo(`{"f":"-inf"}`) == Foo(-float.infinity)); 319 } 320 321 import asdf.asdf; 322 import mir.conv; 323 import std.bigint: BigInt; 324 import std.format: FormatSpec, formatValue; 325 import std.functional; 326 import std.meta; 327 import std.range.primitives; 328 import std.traits; 329 import std.utf; 330 331 deprecated("use mir.serde: SerdeException instead") 332 alias DeserializationException = SerdeException; 333 334 private SerdeException unexpectedKind(string msg = "Unexpected ASDF kind")(ubyte kind) 335 @safe pure nothrow @nogc 336 { 337 import mir.conv: to; 338 static immutable exc(Asdf.Kind kind) = new SerdeException(msg ~ " " ~ kind.to!string); 339 340 switch (kind) 341 { 342 foreach (member; EnumMembers!(Asdf.Kind)) 343 {case member: 344 return exc!member; 345 } 346 default: 347 static immutable ret = new SerdeException("Wrong encoding of ASDF kind"); 348 return ret; 349 } 350 } 351 352 /// JSON serialization function. 353 string serializeToJson(V)(auto ref V value) 354 { 355 return serializeToJsonPretty!""(value); 356 } 357 358 /// 359 unittest 360 { 361 import asdf; 362 363 struct S 364 { 365 string foo; 366 uint bar; 367 } 368 369 assert(serializeToJson(S("str", 4)) == `{"foo":"str","bar":4}`); 370 } 371 372 373 /// JSON serialization function with pretty formatting. 374 string serializeToJsonPretty(string sep = "\t", V)(auto ref V value) 375 { 376 import std.array: appender; 377 import std.functional: forward; 378 379 auto app = appender!(char[]); 380 serializeToJsonPretty!sep(forward!value, app); 381 return cast(string) app.data; 382 } 383 384 /// 385 unittest 386 { 387 import asdf; 388 389 static struct S { int a; } 390 assert(S(4).serializeToJsonPretty == "{\n\t\"a\": 4\n}"); 391 } 392 393 /// JSON serialization function with pretty formatting and custom output range. 394 void serializeToJsonPretty(string sep = "\t", V, O)(auto ref V value, ref O output) 395 if(isOutputRange!(O, const(char)[])) 396 { 397 import std.range.primitives: put; 398 auto ser = jsonSerializer!sep((const(char)[] chars) => put(output, chars)); 399 ser.serializeValue(value); 400 ser.flush; 401 } 402 403 404 /// ASDF serialization function 405 Asdf serializeToAsdf(V)(auto ref V value, size_t initialLength = 32) 406 { 407 auto ser = asdfSerializer(initialLength); 408 ser.serializeValue(value); 409 ser.flush; 410 return ser.app.result; 411 } 412 413 /// 414 unittest 415 { 416 import asdf; 417 import mir.conv: to; 418 419 struct S 420 { 421 string foo; 422 uint bar; 423 } 424 425 assert(serializeToAsdf(S("str", 4)).to!string == `{"foo":"str","bar":4}`); 426 } 427 428 /// Deserialization function 429 V deserialize(V)(Asdf data) 430 { 431 V value; 432 static if (is(V == class)) value = new V; 433 if (auto exc = deserializeValue(data, value)) 434 throw exc; 435 return value; 436 } 437 438 /// ditto 439 V deserialize(V)(in char[] str) 440 { 441 import asdf.jsonparser: parseJson; 442 import std.range: only; 443 return str.parseJson.deserialize!V; 444 } 445 446 /// 447 unittest 448 { 449 struct S 450 { 451 string foo; 452 uint bar; 453 } 454 455 assert(deserialize!S(`{"foo":"str","bar":4}`) == S("str", 4)); 456 } 457 458 /// Proxy for members 459 unittest 460 { 461 struct S 462 { 463 // const(char)[] doesn't reallocate ASDF data. 464 @serdeProxy!(const(char)[]) 465 uint bar; 466 } 467 468 auto json = `{"bar":"4"}`; 469 assert(serializeToJson(S(4)) == json); 470 assert(deserialize!S(json) == S(4)); 471 } 472 473 version(unittest) private 474 { 475 @serdeProxy!ProxyE 476 enum E 477 { 478 none, 479 bar, 480 } 481 482 // const(char)[] doesn't reallocate ASDF data. 483 @serdeProxy!(const(char)[]) 484 struct ProxyE 485 { 486 E e; 487 488 this(E e) 489 { 490 this.e = e; 491 } 492 493 this(in char[] str) 494 { 495 switch(str) 496 { 497 case "NONE": 498 case "NA": 499 case "N/A": 500 e = E.none; 501 break; 502 case "BAR": 503 case "BR": 504 e = E.bar; 505 break; 506 default: 507 throw new Exception("Unknown: " ~ cast(string)str); 508 } 509 } 510 511 string toString() const 512 { 513 if (e == E.none) 514 return "NONE"; 515 else 516 return "BAR"; 517 } 518 519 E opCast(T : E)() 520 { 521 return e; 522 } 523 } 524 525 unittest 526 { 527 assert(serializeToJson(E.bar) == `"BAR"`); 528 assert(`"N/A"`.deserialize!E == E.none); 529 assert(`"NA"`.deserialize!E == E.none); 530 } 531 } 532 533 /// 534 pure unittest 535 { 536 static struct S 537 { 538 @serdeKeys("b", "a") 539 string s; 540 } 541 assert(`{"a":"d"}`.deserialize!S.serializeToJson == `{"b":"d"}`); 542 } 543 544 /// 545 pure unittest 546 { 547 static struct S 548 { 549 @serdeKeys("a") 550 @serdeKeyOut("s") 551 string s; 552 } 553 assert(`{"a":"d"}`.deserialize!S.serializeToJson == `{"s":"d"}`); 554 } 555 556 /// 557 pure unittest 558 { 559 import std.exception; 560 struct S 561 { 562 string field; 563 } 564 assert(`{"field":"val"}`.deserialize!S.field == "val"); 565 assertThrown(`{"other":"val"}`.deserialize!S); 566 } 567 568 /// 569 unittest 570 { 571 import asdf; 572 573 static struct S 574 { 575 @serdeKeyOut("a") 576 string s; 577 } 578 assert(`{"s":"d"}`.deserialize!S.serializeToJson == `{"a":"d"}`); 579 } 580 581 /// 582 unittest 583 { 584 import asdf; 585 586 static struct S 587 { 588 @serdeIgnore 589 string s; 590 } 591 assert(`{"s":"d"}`.deserialize!S.s == null); 592 assert(S("d").serializeToJson == `{}`); 593 } 594 595 /// 596 unittest 597 { 598 import asdf; 599 600 static struct Decor 601 { 602 int candles; // 0 603 float fluff = float.infinity; // inf 604 } 605 606 static struct Cake 607 { 608 @serdeIgnoreDefault 609 string name = "Chocolate Cake"; 610 int slices = 8; 611 float flavor = 1; 612 @serdeIgnoreDefault 613 Decor dec = Decor(20); // { 20, inf } 614 } 615 616 assert(Cake("Normal Cake").serializeToJson == `{"name":"Normal Cake","slices":8,"flavor":1.0}`); 617 auto cake = Cake.init; 618 cake.dec = Decor.init; 619 assert(cake.serializeToJson == `{"slices":8,"flavor":1.0,"dec":{"candles":0,"fluff":"inf"}}`); 620 assert(cake.dec.serializeToJson == `{"candles":0,"fluff":"inf"}`); 621 622 static struct A 623 { 624 @serdeIgnoreDefault 625 string str = "Banana"; 626 int i = 1; 627 } 628 assert(A.init.serializeToJson == `{"i":1}`); 629 630 static struct S 631 { 632 @serdeIgnoreDefault 633 A a; 634 } 635 assert(S.init.serializeToJson == `{}`); 636 assert(S(A("Berry")).serializeToJson == `{"a":{"str":"Berry","i":1}}`); 637 638 static struct D 639 { 640 S s; 641 } 642 assert(D.init.serializeToJson == `{"s":{}}`); 643 assert(D(S(A("Berry"))).serializeToJson == `{"s":{"a":{"str":"Berry","i":1}}}`); 644 assert(D(S(A(null, 0))).serializeToJson == `{"s":{"a":{"str":null,"i":0}}}`); 645 646 static struct F 647 { 648 D d; 649 } 650 assert(F.init.serializeToJson == `{"d":{"s":{}}}`); 651 } 652 653 /// 654 unittest 655 { 656 import asdf; 657 658 static struct S 659 { 660 @serdeIgnoreIn 661 string s; 662 } 663 assert(`{"s":"d"}`.deserialize!S.s == null); 664 assert(S("d").serializeToJson == `{"s":"d"}`); 665 } 666 667 /// 668 unittest 669 { 670 static struct S 671 { 672 @serdeIgnoreOut 673 string s; 674 } 675 assert(`{"s":"d"}`.deserialize!S.s == "d"); 676 assert(S("d").serializeToJson == `{}`); 677 } 678 679 /// 680 unittest 681 { 682 import asdf; 683 684 static struct S 685 { 686 @serdeIgnoreOutIf!`a < 0` 687 int a; 688 } 689 690 assert(serializeToJson(S(3)) == `{"a":3}`, serializeToJson(S(3))); 691 assert(serializeToJson(S(-3)) == `{}`); 692 } 693 694 /// 695 unittest 696 { 697 import asdf; 698 699 import std.uuid; 700 701 static struct S 702 { 703 @serdeScoped 704 @serdeProxy!string 705 UUID id; 706 } 707 assert(`{"id":"8AB3060E-2cba-4f23-b74c-b52db3bdfb46"}`.deserialize!S.id 708 == UUID("8AB3060E-2cba-4f23-b74c-b52db3bdfb46")); 709 } 710 711 /// Proxy type for array of algebraics 712 unittest 713 { 714 import asdf; 715 import mir.algebraic: Variant; 716 717 static struct ObjectA 718 { 719 string name; 720 } 721 static struct ObjectB 722 { 723 double value; 724 } 725 726 alias MyObject = Variant!(ObjectA, ObjectB); 727 728 static struct MyObjectArrayProxy 729 { 730 MyObject[] array; 731 732 this(MyObject[] array) @safe pure nothrow @nogc 733 { 734 this.array = array; 735 } 736 737 T opCast(T : MyObject[])() 738 { 739 return array; 740 } 741 742 void serialize(S)(ref S serializer) const 743 { 744 auto state = serializer.listBegin; 745 foreach (ref e; array) 746 { 747 serializer.elemBegin(); 748 // mir.algebraic has builtin support for serialization. 749 // For other algebraic libraies one can use thier visitor handlers. 750 serializeValue(serializer, e); 751 } 752 serializer.listEnd(state); 753 } 754 755 auto deserializeFromAsdf(Asdf asdfData) 756 { 757 import asdf : deserializeValue; 758 import std.traits : EnumMembers; 759 760 foreach (e; asdfData.byElement) 761 { 762 if (e["name"] != Asdf.init) 763 { 764 array ~= MyObject(deserialize!ObjectA(e)); 765 } 766 else 767 { 768 array ~= MyObject(deserialize!ObjectB(e)); 769 } 770 } 771 772 return SerdeException.init; 773 } 774 } 775 776 static struct SomeObject 777 { 778 @serdeProxy!MyObjectArrayProxy MyObject[] objects; 779 } 780 781 string data = q{{"objects":[{"name":"test"},{"value":1.5}]}}; 782 783 auto value = data.deserialize!SomeObject; 784 assert (value.serializeToJson == data); 785 } 786 787 /// 788 unittest 789 { 790 import asdf; 791 792 import std.range; 793 import std.uuid; 794 795 static struct S 796 { 797 private int count; 798 @serdeLikeList 799 auto numbers() @property // uses `foreach` 800 { 801 return iota(count); 802 } 803 804 @serdeLikeList 805 @serdeProxy!string // input element type of 806 @serdeIgnoreOut 807 Appender!(string[]) strings; //`put` method is used 808 } 809 810 assert(S(5).serializeToJson == `{"numbers":[0,1,2,3,4]}`); 811 assert(`{"strings":["a","b"]}`.deserialize!S.strings.data == ["a","b"]); 812 } 813 814 /// 815 unittest 816 { 817 import asdf; 818 819 static struct M 820 { 821 private int sum; 822 823 // opApply is used for serialization 824 int opApply(int delegate(in char[] key, int val) pure dg) pure 825 { 826 if(auto r = dg("a", 1)) return r; 827 if(auto r = dg("b", 2)) return r; 828 if(auto r = dg("c", 3)) return r; 829 return 0; 830 } 831 832 // opIndexAssign for deserialization 833 void opIndexAssign(int val, string key) pure 834 { 835 sum += val; 836 } 837 } 838 839 static struct S 840 { 841 @serdeLikeStruct 842 @serdeProxy!int 843 M obj; 844 } 845 846 assert(S.init.serializeToJson == `{"obj":{"a":1,"b":2,"c":3}}`); 847 assert(`{"obj":{"a":1,"b":2,"c":9}}`.deserialize!S.obj.sum == 12); 848 } 849 850 /// 851 unittest 852 { 853 import asdf; 854 import std.range; 855 import std.algorithm; 856 import std.conv; 857 858 static struct S 859 { 860 @serdeTransformIn!"a += 2" 861 @serdeTransformOut!(a =>"str".repeat.take(a).joiner("_").to!string) 862 int a; 863 } 864 865 auto s = deserialize!S(`{"a":3}`); 866 assert(s.a == 5); 867 assert(serializeToJson(s) == `{"a":"str_str_str_str_str"}`); 868 } 869 870 /// JSON serialization back-end 871 struct JsonSerializer(string sep, Dg) 872 { 873 import asdf.jsonbuffer; 874 875 static if(sep.length) 876 { 877 private size_t deep; 878 879 private void putSpace() 880 { 881 for(auto k = deep; k; k--) 882 { 883 static if(sep.length == 1) 884 { 885 sink.put(sep[0]); 886 } 887 else 888 { 889 sink.put!sep; 890 } 891 } 892 } 893 } 894 895 896 /// JSON string buffer 897 JsonBuffer!Dg sink; 898 899 /// 900 this(Dg sink) 901 { 902 this.sink = JsonBuffer!Dg(sink); 903 } 904 905 private uint state; 906 907 private void pushState(uint state) 908 { 909 this.state = state; 910 } 911 912 private uint popState() 913 { 914 auto ret = state; 915 state = 0; 916 return ret; 917 } 918 919 private void incState() 920 { 921 if(state++) 922 { 923 static if(sep.length) 924 { 925 sink.put!",\n"; 926 } 927 else 928 { 929 sink.put(','); 930 } 931 } 932 } 933 934 /// Serialization primitives 935 uint structBegin(size_t length = 0) 936 { 937 static if(sep.length) 938 { 939 deep++; 940 sink.put!"{\n"; 941 } 942 else 943 { 944 sink.put('{'); 945 } 946 return popState; 947 } 948 949 ///ditto 950 void structEnd(uint state) 951 { 952 static if(sep.length) 953 { 954 deep--; 955 sink.put('\n'); 956 putSpace; 957 } 958 sink.put('}'); 959 pushState(state); 960 } 961 962 ///ditto 963 uint listBegin(size_t length = 0) 964 { 965 static if(sep.length) 966 { 967 deep++; 968 sink.put!"[\n"; 969 } 970 else 971 { 972 sink.put('['); 973 } 974 return popState; 975 } 976 977 ///ditto 978 void listEnd(uint state) 979 { 980 static if(sep.length) 981 { 982 deep--; 983 sink.put('\n'); 984 putSpace; 985 } 986 sink.put(']'); 987 pushState(state); 988 } 989 990 ///ditto 991 void putEscapedKey(in char[] key) 992 { 993 incState; 994 static if(sep.length) 995 { 996 putSpace; 997 } 998 sink.put('\"'); 999 sink.putSmallEscaped(key); 1000 static if(sep.length) 1001 { 1002 sink.put!"\": "; 1003 } 1004 else 1005 { 1006 sink.put!"\":"; 1007 } 1008 } 1009 1010 ///ditto 1011 void putKey(in char[] key) 1012 { 1013 incState; 1014 static if(sep.length) 1015 { 1016 putSpace; 1017 } 1018 sink.put('\"'); 1019 sink.put(key); 1020 static if(sep.length) 1021 { 1022 sink.put!"\": "; 1023 } 1024 else 1025 { 1026 sink.put!"\":"; 1027 } 1028 } 1029 1030 ///ditto 1031 void putNumberValue(Num)(Num num, FormatSpec!char fmt = FormatSpec!char.init) 1032 { 1033 auto f = &sink.putSmallEscaped; 1034 static if (isNumeric!Num) 1035 { 1036 static struct S 1037 { 1038 typeof(f) fun; 1039 auto put(scope const(char)[] str) 1040 { 1041 fun(str); 1042 } 1043 } 1044 auto app = S(f); 1045 if (fmt == FormatSpec!char.init) 1046 { 1047 import mir.format: print; 1048 print(app, num); 1049 return; 1050 } 1051 } 1052 assumePure((typeof(f) fun) => formatValue(fun, num, fmt))(f); 1053 } 1054 1055 ///ditto 1056 void putValue(typeof(null)) 1057 { 1058 sink.put!"null"; 1059 } 1060 1061 ///ditto 1062 import mir.timestamp: Timestamp; 1063 void putValue(Timestamp timestamp) 1064 { 1065 import mir.format: stringBuf, getData; 1066 putValue(stringBuf() << timestamp << getData); 1067 } 1068 1069 ///ditto 1070 void putValue(bool b) 1071 { 1072 if(b) 1073 sink.put!"true"; 1074 else 1075 sink.put!"false"; 1076 } 1077 1078 ///ditto 1079 void putValue(in char[] str) 1080 { 1081 sink.put('\"'); 1082 sink.put(str); 1083 sink.put('\"'); 1084 } 1085 1086 ///ditto 1087 void putValue(Num)(Num num) 1088 if (isNumeric!Num && !is(Num == enum)) 1089 { 1090 putNumberValue(num); 1091 } 1092 1093 ///ditto 1094 void elemBegin() 1095 { 1096 incState; 1097 static if(sep.length) 1098 { 1099 putSpace; 1100 } 1101 } 1102 1103 ///ditto 1104 void flush() 1105 { 1106 sink.flush; 1107 } 1108 1109 deprecated("Use structBegin instead") alias objectBegin = structBegin; 1110 deprecated("Use structEnd instead") alias objectEnd = structEnd; 1111 deprecated("Use listBegin instead") alias arrayBegin = listBegin; 1112 deprecated("Use listEnd instead") alias arrayEnd = listEnd; 1113 } 1114 1115 /++ 1116 Creates JSON serialization back-end. 1117 Use `sep` equal to `"\t"` or `" "` for pretty formatting. 1118 +/ 1119 auto jsonSerializer(string sep = "", Dg)(scope Dg sink) 1120 { 1121 return JsonSerializer!(sep, Dg)(sink); 1122 } 1123 1124 /// 1125 unittest 1126 { 1127 import asdf; 1128 1129 import std.array; 1130 import std.bigint; 1131 import std.format: singleSpec; 1132 1133 auto app = appender!string; 1134 auto ser = jsonSerializer(&app.put!(const(char)[])); 1135 auto state0 = ser.structBegin; 1136 1137 ser.putEscapedKey("null"); 1138 ser.putValue(null); 1139 1140 ser.putEscapedKey("array"); 1141 auto state1 = ser.listBegin(); 1142 ser.elemBegin; ser.putValue(null); 1143 ser.elemBegin; ser.putValue(123); 1144 ser.elemBegin; ser.putNumberValue(12300000.123, singleSpec("%.10e")); 1145 ser.elemBegin; ser.putValue("\t"); 1146 ser.elemBegin; ser.putValue("\r"); 1147 ser.elemBegin; ser.putValue("\n"); 1148 ser.elemBegin; ser.putNumberValue(BigInt("1234567890")); 1149 ser.listEnd(state1); 1150 1151 ser.structEnd(state0); 1152 ser.flush; 1153 1154 assert(app.data == `{"null":null,"array":[null,123,1.2300000123e+07,"\t","\r","\n",1234567890]}`); 1155 } 1156 1157 unittest 1158 { 1159 import std.array; 1160 import std.bigint; 1161 import std.format: singleSpec; 1162 1163 auto app = appender!string; 1164 auto ser = jsonSerializer!" "(&app.put!(const(char)[])); 1165 auto state0 = ser.structBegin; 1166 1167 ser.putEscapedKey("null"); 1168 ser.putValue(null); 1169 1170 ser.putEscapedKey("array"); 1171 auto state1 = ser.listBegin(); 1172 ser.elemBegin; ser.putValue(null); 1173 ser.elemBegin; ser.putValue(123); 1174 ser.elemBegin; ser.putNumberValue(12300000.123, singleSpec("%.10e")); 1175 ser.elemBegin; ser.putValue("\t"); 1176 ser.elemBegin; ser.putValue("\r"); 1177 ser.elemBegin; ser.putValue("\n"); 1178 ser.elemBegin; ser.putNumberValue(BigInt("1234567890")); 1179 ser.listEnd(state1); 1180 1181 ser.structEnd(state0); 1182 ser.flush; 1183 1184 assert(app.data == 1185 `{ 1186 "null": null, 1187 "array": [ 1188 null, 1189 123, 1190 1.2300000123e+07, 1191 "\t", 1192 "\r", 1193 "\n", 1194 1234567890 1195 ] 1196 }`); 1197 } 1198 1199 /// ASDF serialization back-end 1200 struct AsdfSerializer 1201 { 1202 /// Output buffer 1203 OutputArray app; 1204 1205 import asdf.outputarray; 1206 import asdf.asdf; 1207 private uint state; 1208 1209 pure: 1210 1211 /// Serialization primitives 1212 size_t structBegin(size_t length = 0) 1213 { 1214 app.put1(Asdf.Kind.object); 1215 return app.skip(4); 1216 } 1217 1218 ///ditto 1219 void structEnd(size_t state) 1220 { 1221 app.put4(cast(uint)(app.shift - state - 4), state); 1222 } 1223 1224 ///ditto 1225 size_t listBegin(size_t length = 0) 1226 { 1227 app.put1(Asdf.Kind.array); 1228 return app.skip(4); 1229 } 1230 1231 ///ditto 1232 void listEnd(size_t state) 1233 { 1234 app.put4(cast(uint)(app.shift - state - 4), state); 1235 } 1236 1237 ///ditto 1238 alias putEscapedKey = putKey; 1239 1240 ///ditto 1241 void putKey(in char[] key) 1242 { 1243 auto sh = app.skip(1); 1244 app.put(key); 1245 app.put1(cast(ubyte)(app.shift - sh - 1), sh); 1246 } 1247 1248 ///ditto 1249 void putNumberValue(Num)(Num num, FormatSpec!char fmt = FormatSpec!char.init) pure 1250 { 1251 app.put1(Asdf.Kind.number); 1252 auto sh = app.skip(1); 1253 static if (isNumeric!Num) 1254 { 1255 if (fmt == FormatSpec!char.init) 1256 { 1257 import mir.format: print; 1258 print(app, num); 1259 app.put1(cast(ubyte)(app.shift - sh - 1), sh); 1260 return; 1261 } 1262 } 1263 assumePure((ref OutputArray app) => formatValue(app, num, fmt))(app); 1264 app.put1(cast(ubyte)(app.shift - sh - 1), sh); 1265 } 1266 1267 ///ditto 1268 void putValue(typeof(null)) 1269 { 1270 with(Asdf.Kind) app.put1(null_); 1271 } 1272 1273 ///ditto 1274 void putValue(bool b) 1275 { 1276 with(Asdf.Kind) app.put1(b ? true_ : false_); 1277 } 1278 1279 ///ditto 1280 import mir.timestamp: Timestamp; 1281 void putValue(Timestamp timestamp) 1282 { 1283 import mir.format: stringBuf, getData; 1284 putValue(stringBuf() << timestamp << getData); 1285 } 1286 1287 ///ditto 1288 void putValue(in char[] str) 1289 { 1290 app.put1(Asdf.Kind..string); 1291 auto sh = app.skip(4); 1292 app.put(str); 1293 app.put4(cast(uint)(app.shift - sh - 4), sh); 1294 } 1295 1296 ///ditto 1297 void putValue(Num)(Num num) 1298 if (isNumeric!Num && !is(Num == enum)) 1299 { 1300 putNumberValue(num); 1301 } 1302 1303 /// 1304 void putValue(Num)(const Num value) 1305 if (isNumeric!Num && !is(Num == enum)) 1306 { 1307 import mir.format: print; 1308 import mir.internal.utility: isFloatingPoint; 1309 1310 static if (isFloatingPoint!Num) 1311 { 1312 import mir.math.common: fabs; 1313 1314 if (value.fabs < value.infinity) 1315 print(app, value); 1316 else if (value == Num.infinity) 1317 app.put(`"+inf"`); 1318 else if (value == -Num.infinity) 1319 app.put(`"-inf"`); 1320 else 1321 app.put(`"nan"`); 1322 } 1323 else 1324 print(app, value); 1325 } 1326 1327 ///ditto 1328 static void elemBegin() 1329 { 1330 } 1331 1332 ///ditto 1333 static void flush() 1334 { 1335 } 1336 1337 deprecated("Use structBegin instead") alias objectBegin = structBegin; 1338 deprecated("Use structEnd instead") alias objectEnd = structEnd; 1339 deprecated("Use listBegin instead") alias arrayBegin = listBegin; 1340 deprecated("Use listEnd instead") alias arrayEnd = listEnd; 1341 } 1342 1343 /// Create ASDF serialization back-end 1344 auto asdfSerializer(size_t initialLength = 32) 1345 { 1346 import asdf.outputarray; 1347 return AsdfSerializer(OutputArray(initialLength)); 1348 } 1349 1350 /// 1351 unittest 1352 { 1353 import asdf; 1354 import mir.conv: to; 1355 import std.bigint; 1356 import std.format: singleSpec; 1357 1358 auto ser = asdfSerializer(); 1359 auto state0 = ser.structBegin; 1360 1361 ser.putEscapedKey("null"); 1362 ser.putValue(null); 1363 1364 ser.putKey("array"); 1365 auto state1 = ser.listBegin(); 1366 ser.elemBegin; ser.putValue(null); 1367 ser.elemBegin; ser.putValue(123); 1368 ser.elemBegin; ser.putNumberValue(12300000.123, singleSpec("%.10e")); 1369 ser.elemBegin; ser.putValue("\t"); 1370 ser.elemBegin; ser.putValue("\r"); 1371 ser.elemBegin; ser.putValue("\n"); 1372 ser.elemBegin; ser.putNumberValue(BigInt("1234567890")); 1373 ser.listEnd(state1); 1374 1375 ser.structEnd(state0); 1376 1377 assert(ser.app.result.to!string == `{"null":null,"array":[null,123,1.2300000123e+07,"\t","\r","\n",1234567890]}`); 1378 } 1379 1380 /// `null` value serialization 1381 void serializeValue(S)(ref S serializer, typeof(null)) 1382 { 1383 serializer.putValue(null); 1384 } 1385 1386 /// 1387 unittest 1388 { 1389 import asdf; 1390 1391 assert(serializeToJson(null) == `null`); 1392 } 1393 1394 /// Number serialization 1395 void serializeValue(S, V)(ref S serializer, in V value, FormatSpec!char fmt = FormatSpec!char.init) 1396 if((isNumeric!V && !is(V == enum)) || is(V == BigInt)) 1397 { 1398 static if (isFloatingPoint!V) 1399 { 1400 import std.math : isNaN, isFinite, signbit; 1401 1402 if (isFinite(value)) 1403 serializer.putNumberValue(value, fmt); 1404 else if (value.isNaN) 1405 serializer.putValue(signbit(value) ? "-nan" : "nan"); 1406 else if (value == V.infinity) 1407 serializer.putValue("inf"); 1408 else if (value == -V.infinity) 1409 serializer.putValue("-inf"); 1410 } 1411 else 1412 serializer.putNumberValue(value, fmt); 1413 } 1414 1415 /// 1416 unittest 1417 { 1418 import std.bigint; 1419 1420 assert(serializeToJson(BigInt(123)) == `123`); 1421 assert(serializeToJson(2.40f) == `2.4`); 1422 assert(serializeToJson(float.nan) == `"nan"`); 1423 assert(serializeToJson(float.infinity) == `"inf"`); 1424 assert(serializeToJson(-float.infinity) == `"-inf"`); 1425 } 1426 1427 /// Boolean serialization 1428 void serializeValue(S, V)(ref S serializer, const V value) 1429 if (is(V == bool) && !is(V == enum)) 1430 { 1431 serializer.putValue(value); 1432 } 1433 1434 /// Char serialization 1435 void serializeValue(S, V : char)(ref S serializer, const V value) 1436 if (is(V == char) && !is(V == enum)) 1437 { 1438 auto v = cast(char[1])value; 1439 serializer.putValue(v[]); 1440 } 1441 1442 /// 1443 unittest 1444 { 1445 assert(serializeToJson(true) == `true`); 1446 } 1447 1448 /// Enum serialization 1449 void serializeValue(S, V)(ref S serializer, in V value) 1450 if(is(V == enum)) 1451 { 1452 static if (hasUDA!(V, serdeProxy)) 1453 { 1454 serializer.serializeValue(value.to!(serdeGetProxy!V)); 1455 } 1456 else 1457 { 1458 serializer.putValue(serdeGetKeyOut(value)); 1459 } 1460 } 1461 1462 /// 1463 unittest 1464 { 1465 enum Key { @serdeKeys("FOO", "foo") foo } 1466 assert(serializeToJson(Key.foo) == `"FOO"`); 1467 } 1468 1469 /// String serialization 1470 void serializeValue(S)(ref S serializer, in char[] value) 1471 { 1472 if(value is null) 1473 { 1474 serializer.putValue(null); 1475 return; 1476 } 1477 serializer.putValue(value); 1478 } 1479 1480 /// 1481 unittest 1482 { 1483 assert(serializeToJson("\t \" \\") == `"\t \" \\"`); 1484 } 1485 1486 /// Array serialization 1487 void serializeValue(S, T)(ref S serializer, T[] value) 1488 if(!isSomeChar!T) 1489 { 1490 if(value is null) 1491 { 1492 serializer.putValue(null); 1493 return; 1494 } 1495 auto state = serializer.listBegin(); 1496 foreach (ref elem; value) 1497 { 1498 serializer.elemBegin; 1499 serializer.serializeValue(elem); 1500 } 1501 serializer.listEnd(state); 1502 } 1503 1504 /// Input range serialization 1505 void serializeValue(S, R)(ref S serializer, R value) 1506 if ((isInputRange!R) && 1507 !isSomeChar!(ElementType!R) && 1508 !isDynamicArray!R && 1509 !isStdNullable!R) 1510 { 1511 auto state = serializer.listBegin(); 1512 foreach (ref elem; value) 1513 { 1514 serializer.elemBegin; 1515 serializer.serializeValue(elem); 1516 } 1517 serializer.listEnd(state); 1518 } 1519 1520 /// input range serialization 1521 unittest 1522 { 1523 import std.algorithm : filter; 1524 1525 struct Foo 1526 { 1527 int i; 1528 } 1529 1530 auto ar = [Foo(1), Foo(3), Foo(4), Foo(17)]; 1531 1532 auto filtered1 = ar.filter!"a.i & 1"; 1533 auto filtered2 = ar.filter!"!(a.i & 1)"; 1534 1535 assert(serializeToJson(filtered1) == `[{"i":1},{"i":3},{"i":17}]`); 1536 assert(serializeToJson(filtered2) == `[{"i":4}]`); 1537 } 1538 1539 /// 1540 unittest 1541 { 1542 uint[2] ar = [1, 2]; 1543 assert(serializeToJson(ar) == `[1,2]`); 1544 assert(serializeToJson(ar[]) == `[1,2]`); 1545 assert(serializeToJson(ar[0 .. 0]) == `[]`); 1546 assert(serializeToJson((uint[]).init) == `null`); 1547 } 1548 1549 /// String-value associative array serialization 1550 void serializeValue(S, T)(ref S serializer, auto ref T[string] value) 1551 { 1552 if(value is null) 1553 { 1554 serializer.putValue(null); 1555 return; 1556 } 1557 auto state = serializer.structBegin(); 1558 foreach (key, ref val; value) 1559 { 1560 serializer.putKey(key); 1561 serializer.serializeValue(val); 1562 } 1563 serializer.structEnd(state); 1564 } 1565 1566 /// 1567 unittest 1568 { 1569 uint[string] ar = ["a" : 1]; 1570 assert(serializeToJson(ar) == `{"a":1}`); 1571 ar.remove("a"); 1572 assert(serializeToJson(ar) == `{}`); 1573 assert(serializeToJson((uint[string]).init) == `null`); 1574 } 1575 1576 /// Enumeration-value associative array serialization 1577 void serializeValue(S, V : const T[K], T, K)(ref S serializer, V value) 1578 if(is(K == enum)) 1579 { 1580 if(value is null) 1581 { 1582 serializer.putValue(null); 1583 return; 1584 } 1585 auto state = serializer.structBegin(); 1586 foreach (key, ref val; value) 1587 { 1588 serializer.putEscapedKey(key.to!string); 1589 serializer.putValue(val); 1590 } 1591 serializer.structEnd(state); 1592 } 1593 1594 /// 1595 unittest 1596 { 1597 enum E { a, b } 1598 uint[E] ar = [E.a : 1]; 1599 assert(serializeToJson(ar) == `{"a":1}`); 1600 ar.remove(E.a); 1601 assert(serializeToJson(ar) == `{}`); 1602 assert(serializeToJson((uint[string]).init) == `null`); 1603 } 1604 1605 /// integral typed value associative array serialization 1606 void serializeValue(S, V : const T[K], T, K)(ref S serializer, V value) 1607 if((isIntegral!K) && !is(K == enum)) 1608 { 1609 if(value is null) 1610 { 1611 serializer.putValue(null); 1612 return; 1613 } 1614 char[40] buffer = void; 1615 auto state = serializer.structBegin(); 1616 foreach (key, ref val; value) 1617 { 1618 import std.format : sformat; 1619 auto str = sformat(buffer[], "%d", key); 1620 serializer.putEscapedKey(str); 1621 .serializeValue(serializer, val); 1622 } 1623 serializer.structEnd(state); 1624 } 1625 1626 /// 1627 unittest 1628 { 1629 uint[short] ar = [256 : 1]; 1630 assert(serializeToJson(ar) == `{"256":1}`); 1631 ar.remove(256); 1632 assert(serializeToJson(ar) == `{}`); 1633 assert(serializeToJson((uint[string]).init) == `null`); 1634 assert(deserialize!(uint[short])(`{"256":1}`) == cast(uint[short]) [256 : 1]); 1635 } 1636 1637 /// Nullable type serialization 1638 void serializeValue(S, N)(ref S serializer, auto ref N value) 1639 if (isStdNullable!N && !isVariant!N) 1640 { 1641 if(value.isNull) 1642 { 1643 serializer.putValue(null); 1644 return; 1645 } 1646 serializer.serializeValue(value.get); 1647 } 1648 1649 /// 1650 unittest 1651 { 1652 import std.typecons; 1653 1654 struct Nested 1655 { 1656 float f; 1657 } 1658 1659 struct T 1660 { 1661 string str; 1662 Nullable!Nested nested; 1663 } 1664 1665 T t; 1666 assert(t.serializeToJson == `{"str":null,"nested":null}`); 1667 t.str = "txt"; 1668 t.nested = Nested(123); 1669 assert(t.serializeToJson == `{"str":"txt","nested":{"f":123.0}}`); 1670 } 1671 1672 /// Struct and class type serialization 1673 void serializeValue(S, V)(ref S serializer, auto ref V value) 1674 if((!isStdNullable!V || isVariant!V) && isAggregateType!V && !is(V : BigInt) && !isInputRange!V) 1675 { 1676 import mir.timestamp: Timestamp; 1677 import mir.algebraic : Algebraic; 1678 import mir.string_map : isStringMap; 1679 static if(is(V == class) || is(V == interface)) 1680 { 1681 if(value is null) 1682 { 1683 serializer.putValue(null); 1684 return; 1685 } 1686 } 1687 1688 static if (is(Unqual!V == Timestamp)) 1689 { 1690 serializer.putValue(value); 1691 } 1692 else 1693 static if (is(Unqual!V == Algebraic!TypeSet, TypeSet...)) 1694 { 1695 import mir.algebraic: visit; 1696 value.visit!((auto ref v) { 1697 alias T = typeof(v); 1698 static if (isStringMap!T ) 1699 { 1700 if(v == v.init) 1701 { 1702 auto valState = serializer.structBegin(); 1703 serializer.structEnd(valState); 1704 return; 1705 } 1706 } 1707 else 1708 static if (isAssociativeArray!T) 1709 { 1710 if(v is null) 1711 { 1712 auto valState = serializer.structBegin(); 1713 serializer.structEnd(valState); 1714 return; 1715 } 1716 } 1717 else 1718 static if (isSomeString!T) 1719 { 1720 if(v is null) 1721 { 1722 serializer.putValue(""); 1723 return; 1724 } 1725 } 1726 else 1727 static if (isDynamicArray!T) 1728 { 1729 if(v is null) 1730 { 1731 auto valState = serializer.listBegin(); 1732 serializer.listEnd(valState); 1733 return; 1734 } 1735 } 1736 .serializeValue(serializer, v); 1737 }); 1738 } 1739 else 1740 static if (isStringMap!V) 1741 { 1742 if(value == value.init) 1743 { 1744 serializer.putValue(null); 1745 return; 1746 } 1747 auto valState = serializer.structBegin(); 1748 foreach (i, key; value.keys) 1749 { 1750 serializer.putKey(key); 1751 serializer.serializeValue(value.values[i]); 1752 } 1753 serializer.structEnd(valState); 1754 return; 1755 } 1756 else 1757 static if(__traits(hasMember, V, "serialize")) 1758 { 1759 value.serialize(serializer); 1760 } 1761 else 1762 static if (hasUDA!(V, serdeProxy)) 1763 { 1764 serializer.serializeValue(value.to!(serdeGetProxy!V)); 1765 } 1766 else 1767 { 1768 auto state = serializer.structBegin(); 1769 foreach(member; aliasSeqOf!(SerializableMembers!V)) 1770 {{ 1771 enum key = serdeGetKeyOut!(__traits(getMember, value, member)); 1772 1773 static if (key !is null) 1774 { 1775 static if (hasUDA!(__traits(getMember, value, member), serdeIgnoreDefault)) 1776 { 1777 if (__traits(getMember, value, member) == __traits(getMember, V.init, member)) 1778 continue; 1779 } 1780 1781 static if(hasUDA!(__traits(getMember, value, member), serdeIgnoreOutIf)) 1782 { 1783 alias pred = serdeGetIgnoreOutIf!(__traits(getMember, value, member)); 1784 if (pred(__traits(getMember, value, member))) 1785 continue; 1786 } 1787 static if(hasUDA!(__traits(getMember, value, member), serdeTransformOut)) 1788 { 1789 alias f = serdeGetTransformOut!(__traits(getMember, value, member)); 1790 auto val = f(__traits(getMember, value, member)); 1791 } 1792 else 1793 { 1794 auto val = __traits(getMember, value, member); 1795 } 1796 1797 serializer.putEscapedKey(key); 1798 1799 static if(hasUDA!(__traits(getMember, value, member), serdeLikeList)) 1800 { 1801 alias V = typeof(val); 1802 static if(is(V == interface) || is(V == class) || is(V : E[], E)) 1803 { 1804 if(val is null) 1805 { 1806 serializer.putValue(null); 1807 continue; 1808 } 1809 } 1810 auto valState = serializer.listBegin(); 1811 foreach (ref elem; val) 1812 { 1813 serializer.elemBegin; 1814 serializer.serializeValue(elem); 1815 } 1816 serializer.listEnd(valState); 1817 } 1818 else 1819 static if(hasUDA!(__traits(getMember, value, member), serdeLikeStruct)) 1820 { 1821 static if(is(V == interface) || is(V == class) || is(V : E[T], E, T)) 1822 { 1823 if(val is null) 1824 { 1825 serializer.putValue(null); 1826 continue F; 1827 } 1828 } 1829 auto valState = serializer.structBegin(); 1830 foreach (key, elem; val) 1831 { 1832 serializer.putKey(key); 1833 serializer.serializeValue(elem); 1834 } 1835 serializer.structEnd(valState); 1836 } 1837 else 1838 static if(hasUDA!(__traits(getMember, value, member), serdeProxy)) 1839 { 1840 serializer.serializeValue(val.to!(serdeGetProxy!(__traits(getMember, value, member)))); 1841 } 1842 else 1843 { 1844 serializer.serializeValue(val); 1845 } 1846 } 1847 }} 1848 static if(__traits(hasMember, V, "finalizeSerialization")) 1849 { 1850 value.finalizeSerialization(serializer); 1851 } 1852 serializer.structEnd(state); 1853 } 1854 } 1855 1856 /// Alias this support 1857 unittest 1858 { 1859 struct S 1860 { 1861 int u; 1862 } 1863 1864 struct C 1865 { 1866 int b; 1867 S s; 1868 alias s this; 1869 } 1870 1871 assert(C(4, S(3)).serializeToJson == `{"u":3,"b":4}`); 1872 } 1873 1874 /// Custom `serialize` 1875 unittest 1876 { 1877 import mir.conv: to; 1878 1879 struct S 1880 { 1881 void serialize(S)(ref S serializer) const 1882 { 1883 auto state = serializer.structBegin; 1884 serializer.putEscapedKey("foo"); 1885 serializer.putValue("bar"); 1886 serializer.structEnd(state); 1887 } 1888 } 1889 enum json = `{"foo":"bar"}`; 1890 assert(serializeToJson(S()) == json); 1891 assert(serializeToAsdf(S()).to!string == json); 1892 } 1893 1894 /// $(GMREF mir-core, mir, algebraic) support. 1895 unittest 1896 { 1897 import mir.algebraic: Variant, Nullable, This; 1898 alias V = Nullable!(double, string, This[], This[string]); 1899 V v; 1900 assert(v.serializeToJson == "null", v.serializeToJson); 1901 v = [V(2), V("str"), V(["key":V(1.0)])]; 1902 assert(v.serializeToJson == `[2.0,"str",{"key":1.0}]`); 1903 } 1904 1905 /// $(GMREF mir-core, mir, algebraic) with manual serialization. 1906 unittest 1907 { 1908 import asdf.asdf; 1909 1910 static struct Response 1911 { 1912 import mir.algebraic: Variant; 1913 1914 static union Response_ 1915 { 1916 double double_; 1917 immutable(char)[] string; 1918 Response[] array; 1919 Response[immutable(char)[]] table; 1920 } 1921 1922 alias Union = Variant!Response_; 1923 1924 Union data; 1925 alias Tag = Union.Kind; 1926 // propogates opEquals, opAssign, and other primitives 1927 alias data this; 1928 1929 static foreach (T; Union.AllowedTypes) 1930 this(T v) @safe pure nothrow @nogc { data = v; } 1931 1932 void serialize(S)(ref S serializer) const 1933 { 1934 import asdf: serializeValue; 1935 import mir.algebraic: visit; 1936 1937 auto o = serializer.structBegin(); 1938 serializer.putKey("tag"); 1939 serializer.serializeValue(kind); 1940 serializer.putKey("data"); 1941 data.visit!( 1942 (double v) => serializer.serializeValue(v), // specialization for double if required 1943 (const Response[string] v) => serializer.serializeValue(cast(const(Response)[string])v), 1944 (v) => serializer.serializeValue(v), 1945 ); 1946 serializer.structEnd(o); 1947 } 1948 1949 SerdeException deserializeFromAsdf(Asdf asdfData) 1950 { 1951 import asdf : deserializeValue; 1952 import std.traits : EnumMembers; 1953 1954 Tag tag; 1955 if (auto e = asdfData["tag"].deserializeValue(tag)) 1956 return e; 1957 final switch (tag) 1958 { 1959 foreach (m; EnumMembers!Tag) 1960 { 1961 case m: { 1962 alias T = Union.AllowedTypes[m]; 1963 data = T.init; 1964 if (auto e = asdfData["data"].deserializeValue(data.trustedGet!T)) 1965 return e; 1966 break; 1967 } 1968 } 1969 } 1970 return null; 1971 } 1972 } 1973 1974 Response v = 3.0; 1975 assert(v.kind == Response.Tag.double_); 1976 v = "str"; 1977 assert(v == "str"); 1978 1979 import asdf; 1980 assert(v.serializeToJson == `{"tag":"string","data":"str"}`); 1981 v = Response.init; 1982 v = `{"tag":"array","data":[{"tag":"string","data":"S"}]}`.deserialize!Response; 1983 assert(v.kind == Response.Tag.array); 1984 assert(v.get!(Response[])[0] == "S"); 1985 } 1986 1987 /// Deserialize `null` value 1988 SerdeException deserializeValue(T : typeof(null))(Asdf data, T) 1989 { 1990 auto kind = data.kind; 1991 if(kind != Asdf.Kind.null_) 1992 return unexpectedKind(kind); 1993 return null; 1994 } 1995 1996 /// 1997 unittest 1998 { 1999 assert(deserializeValue(serializeToAsdf(null), null) is null); 2000 } 2001 2002 /// Deserialize boolean value 2003 SerdeException deserializeValue(T : bool)(Asdf data, ref T value) pure @safe 2004 { 2005 auto kind = data.kind; 2006 with(Asdf.Kind) switch(kind) 2007 { 2008 case false_: 2009 value = false; 2010 return null; 2011 case true_: 2012 value = true; 2013 return null; 2014 default: 2015 return unexpectedKind(kind); 2016 } 2017 } 2018 2019 /// 2020 pure unittest 2021 { 2022 assert(deserialize!bool(serializeToAsdf(true))); 2023 assert(deserialize!bool(serializeToJson(true))); 2024 } 2025 2026 /++ 2027 Deserialize numeric value. 2028 2029 Special_deserialisation_string_values: 2030 2031 $(TABLE 2032 $(TR $(TD `"+NAN"`)) 2033 $(TR $(TD `"+NaN"`)) 2034 $(TR $(TD `"+nan"`)) 2035 $(TR $(TD `"-NAN"`)) 2036 $(TR $(TD `"-NaN"`)) 2037 $(TR $(TD `"-nan"`)) 2038 $(TR $(TD `"NAN"`)) 2039 $(TR $(TD `"NaN"`)) 2040 $(TR $(TD `"nan"`)) 2041 $(TR $(TD `"+INF"`)) 2042 $(TR $(TD `"+Inf"`)) 2043 $(TR $(TD `"+inf"`)) 2044 $(TR $(TD `"-INF"`)) 2045 $(TR $(TD `"-Inf"`)) 2046 $(TR $(TD `"-inf"`)) 2047 $(TR $(TD `"INF"`)) 2048 $(TR $(TD `"Inf"`)) 2049 $(TR $(TD `"inf"`)) 2050 ) 2051 2052 +/ 2053 SerdeException deserializeValue(V)(Asdf data, ref V value) 2054 if((isNumeric!V && !is(V == enum))) 2055 { 2056 auto kind = data.kind; 2057 2058 static if (isFloatingPoint!V) 2059 { 2060 if (kind == Asdf.Kind.null_) 2061 { 2062 value = V.nan; 2063 return null; 2064 } 2065 if (kind == Asdf.Kind..string) 2066 { 2067 const(char)[] v; 2068 .deserializeScopedString(data, v); 2069 switch (v) 2070 { 2071 case "+NAN": 2072 case "+NaN": 2073 case "+nan": 2074 case "-NAN": 2075 case "-NaN": 2076 case "-nan": 2077 case "NAN": 2078 case "NaN": 2079 case "nan": 2080 value = V.nan; 2081 return null; 2082 case "+INF": 2083 case "+Inf": 2084 case "+inf": 2085 case "INF": 2086 case "Inf": 2087 case "inf": 2088 value = V.infinity; 2089 return null; 2090 case "-INF": 2091 case "-Inf": 2092 case "-inf": 2093 value = -V.infinity; 2094 return null; 2095 default: 2096 import mir.conv : to; 2097 value = data.to!V; 2098 return null; 2099 } 2100 } 2101 } 2102 2103 if(kind != Asdf.Kind.number) 2104 return unexpectedKind(kind); 2105 2106 static if (isFloatingPoint!V) 2107 { 2108 import mir.bignum.internal.dec2float: decimalToFloatImpl; 2109 import mir.bignum.internal.parse: parseJsonNumberImpl; 2110 auto result = (cast(string) data.data[2 .. $]).parseJsonNumberImpl; 2111 if (!result.success) 2112 throw new Exception("Failed to deserialize number"); 2113 2114 auto fp = decimalToFloatImpl!(Unqual!V)(result.coefficient, result.exponent); 2115 if (result.sign) 2116 fp = -fp; 2117 value = fp; 2118 } 2119 else 2120 { 2121 value = (cast(string) data.data[2 .. $]).to!V; 2122 } 2123 return null; 2124 } 2125 2126 /// 2127 unittest 2128 { 2129 import std.bigint; 2130 2131 assert(deserialize!ulong (serializeToAsdf(20)) == ulong (20)); 2132 assert(deserialize!ulong (serializeToJson(20)) == ulong (20)); 2133 assert(deserialize!double(serializeToAsdf(20)) == double(20)); 2134 assert(deserialize!double(serializeToJson(20)) == double(20)); 2135 assert(deserialize!BigInt(serializeToAsdf(20)) == BigInt(20)); 2136 assert(deserialize!BigInt(serializeToJson(20)) == BigInt(20)); 2137 2138 assert(deserialize!float (serializeToJson ("2.40")) == float (2.40)); 2139 assert(deserialize!double(serializeToJson ("2.40")) == double(2.40)); 2140 assert(deserialize!double(serializeToAsdf("-2.40")) == double(-2.40)); 2141 2142 import std.math : isNaN, isInfinity; 2143 assert(deserialize!float (serializeToJson ("+NaN")).isNaN); 2144 assert(deserialize!float (serializeToJson ("INF")).isInfinity); 2145 assert(deserialize!float (serializeToJson ("-inf")).isInfinity); 2146 } 2147 2148 /// Deserialize enum value 2149 SerdeException deserializeValue(V)(Asdf data, ref V value) 2150 if(is(V == enum)) 2151 { 2152 static if (hasUDA!(V, serdeProxy)) 2153 { 2154 serdeGetProxy!V proxy; 2155 enum S = hasUDA!(value, serdeScoped) && __traits(compiles, .deserializeScopedString(data, proxy)); 2156 alias Fun = Select!(S, .deserializeScopedString, .deserializeValue); 2157 Fun(data, proxy); 2158 value = proxy.to!V; 2159 } 2160 else 2161 { 2162 string s; 2163 data.deserializeScopedString(s); 2164 import mir.ndslice.fuse: fuse; 2165 import mir.array.allocation: array; 2166 import mir.ndslice.topology: map; 2167 static immutable allowedKeys = [EnumMembers!V].map!serdeGetKeysIn.array; 2168 if (!serdeParseEnum(s, value)) 2169 throw new Exception("Unable to deserialize string '" ~ s ~ "' to " ~ V.stringof ~ "Allowed keys:" ~ allowedKeys.stringof); 2170 } 2171 return null; 2172 } 2173 2174 /// 2175 unittest 2176 { 2177 @serdeIgnoreCase enum Key { foo } 2178 assert(deserialize!Key(`"FOO"`) == Key.foo); 2179 assert(deserialize!Key(serializeToAsdf("foo")) == Key.foo); 2180 } 2181 2182 /++ 2183 Deserializes scoped string value. 2184 This function does not allocate a new string and just make a raw cast of ASDF data. 2185 +/ 2186 SerdeException deserializeScopedString(V : const(char)[])(Asdf data, ref V value) 2187 { 2188 auto kind = data.kind; 2189 with(Asdf.Kind) switch(kind) 2190 { 2191 case string: 2192 value = cast(V) data.data[5 .. $]; 2193 return null; 2194 case null_: 2195 value = null; 2196 return null; 2197 default: 2198 return unexpectedKind(kind); 2199 } 2200 } 2201 2202 /++ 2203 Deserializes string value. 2204 This function allocates new string. 2205 +/ 2206 SerdeException deserializeValue(V)(Asdf data, ref V value) 2207 if(is(V : const(char)[]) && !isAggregateType!V && !is(V == enum) && !isStdNullable!V) 2208 { 2209 auto kind = data.kind; 2210 with(Asdf.Kind) switch(kind) 2211 { 2212 case string: 2213 value = (() @trusted => cast(V) (data.data[5 .. $]).dup)(); 2214 return null; 2215 case null_: 2216 value = null; 2217 return null; 2218 default: 2219 return unexpectedKind(kind); 2220 } 2221 } 2222 2223 // issue #94/#95/#97 2224 /// String enums supports only enum keys 2225 unittest 2226 { 2227 enum SimpleEnum : string 2228 { 2229 @serdeKeys("se1", "se1value") 2230 se1 = "se1value", 2231 2232 @serdeKeys("se2", "se2value") 2233 se2 = "se2value", 2234 2235 @serdeKeys("se3", "se3value") 2236 se3 = "se3value", 2237 } 2238 2239 struct Simple 2240 { 2241 SimpleEnum en; 2242 SimpleEnum ex; 2243 } 2244 2245 Simple simple = `{"en":"se2", "ex":"se3value"}`.deserialize!Simple; 2246 assert(simple.en == SimpleEnum.se2); 2247 assert(simple.ex == SimpleEnum.se3); 2248 } 2249 2250 /// issue #115 2251 unittest 2252 { 2253 import asdf; 2254 import std.typecons; 2255 2256 struct Example 2257 { 2258 @serdeOptional 2259 Nullable!string field1; 2260 } 2261 2262 assert(`{}`.deserialize!Example == Example()); 2263 assert(Example().serializeToJson == `{"field1":null}`); 2264 } 2265 2266 /// 2267 unittest 2268 { 2269 assert(deserialize!string(serializeToJson(null)) is null); 2270 assert(deserialize!string(serializeToAsdf(null)) is null); 2271 assert(deserialize!string(serializeToJson("\tbar")) == "\tbar"); 2272 assert(deserialize!string(serializeToAsdf("\"bar")) == "\"bar"); 2273 } 2274 2275 /// Deserialize single char 2276 SerdeException deserializeValue(V)(Asdf data, ref V value) 2277 if (is(V == char) && !is(V == enum)) 2278 { 2279 return deserializeValue(data, *(()@trusted=> cast(char[1]*)&value)()); 2280 } 2281 2282 /// 2283 unittest 2284 { 2285 assert(deserialize!char(`"a"`) == 'a'); 2286 assert(deserialize!byte(`-4`) == -4); // regression control 2287 } 2288 2289 /// Deserialize array 2290 SerdeException deserializeValue(V : T[], T)(Asdf data, ref V value) 2291 if(!isSomeChar!T && !isStaticArray!V) 2292 { 2293 const kind = data.kind; 2294 with(Asdf.Kind) switch(kind) 2295 { 2296 case array: 2297 import std.algorithm.searching: count; 2298 auto elems = data.byElement; 2299 // create array of properly initialized (by means of ctor) elements 2300 static if (__traits(compiles, {value = new T[100];})) 2301 { 2302 value = new T[elems.save.count]; 2303 foreach(ref e; value) 2304 { 2305 static if(is(T == class)) e = new T; 2306 if (auto exc = .deserializeValue(elems.front, e)) 2307 return exc; 2308 elems.popFront; 2309 } 2310 } 2311 else 2312 static assert(0, "Type `" ~ T.stringof ~ "` should have default value!"); 2313 assert(elems.empty); 2314 return null; 2315 case null_: 2316 value = null; 2317 return null; 2318 default: 2319 return unexpectedKind(kind); 2320 } 2321 } 2322 2323 /// 2324 unittest 2325 { 2326 assert(deserialize!(int[])(serializeToJson(null)) is null); 2327 assert(deserialize!(int[])(serializeToAsdf(null)) is null); 2328 assert(deserialize!(int[])(serializeToJson([1, 3, 4])) == [1, 3, 4]); 2329 assert(deserialize!(int[])(serializeToAsdf([1, 3, 4])) == [1, 3, 4]); 2330 } 2331 2332 /// Deserialize static array 2333 SerdeException deserializeValue(V : T[N], T, size_t N)(Asdf data, ref V value) 2334 { 2335 auto kind = data.kind; 2336 with(Asdf.Kind) switch(kind) 2337 { 2338 static if(is(Unqual!T == char)) 2339 { 2340 case string: 2341 auto str = cast(immutable(char)[]) data; 2342 // if source is shorter than destination fill the rest by zeros 2343 // if source is longer copy only needed part of it 2344 if (str.length > value.length) 2345 str = str[0..value.length]; 2346 else 2347 value[] = '\0'; 2348 2349 import std.algorithm : copy; 2350 copy(str, value[]); 2351 return null; 2352 } 2353 case array: 2354 auto elems = data.byElement; 2355 foreach(ref e; value) 2356 { 2357 if(elems.empty) 2358 return null; 2359 if (auto exc = .deserializeValue(elems.front, e)) 2360 return exc; 2361 elems.popFront; 2362 } 2363 return null; 2364 case null_: 2365 return null; 2366 default: 2367 return unexpectedKind!("Failed to deserialize value of " ~ V.stringof)(kind); 2368 } 2369 } 2370 2371 /// 2372 unittest 2373 { 2374 assert(deserialize!(int[4])(serializeToJson(null)) == [0, 0, 0, 0]); 2375 assert(deserialize!(int[4])(serializeToAsdf(null)) == [0, 0, 0, 0]); 2376 assert(deserialize!(int[4])(serializeToJson([1, 3, 4])) == [1, 3, 4, 0]); 2377 assert(deserialize!(int[4])(serializeToAsdf([1, 3, 4])) == [1, 3, 4, 0]); 2378 assert(deserialize!(int[2])(serializeToJson([1, 3, 4])) == [1, 3]); 2379 assert(deserialize!(int[2])(serializeToAsdf([1, 3, 4])) == [1, 3]); 2380 2381 assert(deserialize!(char[2])(serializeToAsdf(['a','b'])) == ['a','b']); 2382 assert(deserialize!(char[2])(serializeToAsdf(['a','\0'])) == ['a','\0']); 2383 assert(deserialize!(char[2])(serializeToAsdf(['a','\255'])) == ['a','\255']); 2384 assert(deserialize!(char[2])(serializeToAsdf(['\255'])) == ['\255','\0']); 2385 assert(deserialize!(char[2])(serializeToAsdf(['\255', '\255', '\255'])) == ['\255','\255']); 2386 } 2387 2388 /// AA with value of aggregate type 2389 unittest 2390 { 2391 struct Foo 2392 { 2393 2394 } 2395 2396 assert (deserialize!(Foo[int])(serializeToJson([1: Foo()])) == [1:Foo()]); 2397 } 2398 2399 /// Deserialize string-value associative array 2400 SerdeException deserializeValue(V : T[string], T)(Asdf data, ref V value) 2401 { 2402 auto kind = data.kind; 2403 with(Asdf.Kind) switch(kind) 2404 { 2405 case object: 2406 foreach(elem; data.byKeyValue) 2407 { 2408 T v; 2409 if (auto exc = .deserializeValue(elem.value, v)) 2410 return exc; 2411 value[elem.key.idup] = v; 2412 } 2413 return null; 2414 case null_: 2415 value = null; 2416 return null; 2417 default: 2418 return unexpectedKind(kind); 2419 } 2420 } 2421 2422 /// 2423 unittest 2424 { 2425 assert(deserialize!(int[string])(serializeToJson(null)) is null); 2426 assert(deserialize!(int[string])(serializeToAsdf(null)) is null); 2427 assert(deserialize!(int[string])(serializeToJson(["a" : 1, "b" : 2])) == ["a" : 1, "b" : 2]); 2428 assert(deserialize!(int[string])(serializeToAsdf(["a" : 1, "b" : 2])) == ["a" : 1, "b" : 2]); 2429 } 2430 2431 unittest 2432 { 2433 int[string] r = ["a" : 1]; 2434 serializeToAsdf(null).deserializeValue(r); 2435 assert(r is null); 2436 } 2437 2438 /// Deserialize enumeration-value associative array 2439 SerdeException deserializeValue(V : T[E], T, E)(Asdf data, ref V value) 2440 if(is(E == enum)) 2441 { 2442 auto kind = data.kind; 2443 with(Asdf.Kind) switch(kind) 2444 { 2445 case object: 2446 foreach(elem; data.byKeyValue) 2447 { 2448 T v; 2449 if (auto exc = .deserializeValue(elem.value, v)) 2450 return exc; 2451 value[elem.key.to!E] = v; 2452 } 2453 return null; 2454 case null_: 2455 value = null; 2456 return null; 2457 default: 2458 return unexpectedKind(kind); 2459 } 2460 } 2461 2462 /// 2463 unittest 2464 { 2465 enum E {a, b} 2466 assert(deserialize!(int[E])(serializeToJson(null)) is null); 2467 assert(deserialize!(int[E])(serializeToAsdf(null)) is null); 2468 assert(deserialize!(int[E])(serializeToJson([E.a : 1, E.b : 2])) == [E.a : 1, E.b : 2]); 2469 assert(deserialize!(int[E])(serializeToAsdf([E.a : 1, E.b : 2])) == [E.a : 1, E.b : 2]); 2470 } 2471 2472 unittest 2473 { 2474 enum E {a, b} 2475 int[E] r = [E.a : 1]; 2476 serializeToAsdf(null).deserializeValue(r); 2477 assert(r is null); 2478 } 2479 2480 /// Deserialize associative array with integral type key 2481 SerdeException deserializeValue(V : T[K], T, K)(Asdf data, ref V value) 2482 if((isIntegral!K) && !is(K == enum)) 2483 { 2484 auto kind = data.kind; 2485 with(Asdf.Kind) switch(kind) 2486 { 2487 case object: 2488 foreach(elem; data.byKeyValue) 2489 { 2490 T v; 2491 if (auto exc = .deserializeValue(elem.value, v)) 2492 return exc; 2493 value[elem.key.to!K] = v; 2494 } 2495 return null; 2496 case null_: 2497 value = null; 2498 return null; 2499 default: 2500 return unexpectedKind(kind); 2501 } 2502 } 2503 2504 /// 2505 unittest 2506 { 2507 assert(deserialize!(int[int])(serializeToJson(null)) is null); 2508 assert(deserialize!(int[int])(serializeToAsdf(null)) is null); 2509 assert(deserialize!(int[int])(serializeToJson([2 : 1, 40 : 2])) == [2 : 1, 40 : 2]); 2510 assert(deserialize!(int[int])(serializeToAsdf([2 : 1, 40 : 2])) == [2 : 1, 40 : 2]); 2511 } 2512 2513 unittest 2514 { 2515 int[int] r = [3 : 1]; 2516 serializeToAsdf(null).deserializeValue(r); 2517 assert(r is null); 2518 } 2519 2520 /// 2521 unittest 2522 { 2523 import std.typecons; 2524 2525 struct Nested 2526 { 2527 float f; 2528 } 2529 2530 struct T 2531 { 2532 string str; 2533 Nullable!Nested nested; 2534 @serdeOptional 2535 Nullable!bool nval; 2536 } 2537 2538 T t; 2539 assert(deserialize!T(`{"str":null,"nested":null}`) == t); 2540 t.str = "txt"; 2541 t.nested = Nested(123); 2542 t.nval = false; 2543 assert(deserialize!T(`{"str":"txt","nested":{"f":123},"nval":false}`) == t); 2544 } 2545 2546 struct Impl 2547 { 2548 @safe pure @nogc static: 2549 2550 enum customDeserializeValueMehtodName = "deserializeFromAsdf"; 2551 2552 bool isAnyNull(Asdf data) 2553 { 2554 return data.kind == Asdf.Kind.null_; 2555 } 2556 2557 bool isObjectNull(Asdf data) 2558 { 2559 return data.kind == Asdf.Kind.null_; 2560 } 2561 2562 bool isObject(Asdf data) 2563 { 2564 return data.kind == Asdf.Kind.object; 2565 } 2566 2567 SerdeException unexpectedData(string msg)(Asdf data) 2568 { 2569 return unexpectedKind(data.kind); 2570 } 2571 } 2572 2573 /// Deserialize aggregate value 2574 SerdeException deserializeValue(V)(Asdf data, ref V value) 2575 if(isAggregateType!V) 2576 { 2577 import mir.algebraic; 2578 import mir.string_map; 2579 import mir.timestamp; 2580 static if (is(V == Timestamp)) 2581 { 2582 const(char)[] str; 2583 if (auto exc = deserializeValue(data, str)) 2584 return exc; 2585 value = Timestamp(str); 2586 return null; 2587 } 2588 else 2589 static if (is(V == StringMap!T, T)) 2590 { 2591 auto kind = data.kind; 2592 with(Asdf.Kind) switch(kind) 2593 { 2594 case object: 2595 foreach(elem; data.byKeyValue) 2596 { 2597 T v; 2598 if (auto exc = .deserializeValue(elem.value, v)) 2599 return exc; 2600 value[elem.key.idup] = v; 2601 } 2602 return null; 2603 case null_: 2604 value = null; 2605 return null; 2606 default: 2607 return unexpectedKind(kind); 2608 } 2609 } 2610 else 2611 static if (is(V == Algebraic!TypeSet, TypeSet...)) 2612 { 2613 import std.meta: anySatisfy, Filter; 2614 import mir.internal.meta: Contains; 2615 alias Types = V.AllowedTypes; 2616 alias contains = Contains!Types; 2617 import mir.algebraic: isNullable; 2618 static if (isNullable!V && TypeSet.length == 2) 2619 { 2620 if (data.kind == Asdf.Kind.null_) 2621 { 2622 value = null; 2623 return null; 2624 } 2625 2626 V.AllowedTypes[1] payload; 2627 if (auto exc = .deserializeValue(data, payload)) 2628 return exc; 2629 value = payload; 2630 return null; 2631 } 2632 else 2633 switch (data.kind) 2634 { 2635 static if (contains!(typeof(null))) 2636 { 2637 case Asdf.Kind.null_: 2638 { 2639 value = null; 2640 return null; 2641 } 2642 } 2643 2644 static if (contains!bool) 2645 { 2646 case Asdf.Kind.true_: 2647 { 2648 value = true; 2649 return null; 2650 } 2651 case Asdf.Kind.false_: 2652 { 2653 value = false; 2654 return null; 2655 } 2656 } 2657 2658 static if (contains!string) 2659 { 2660 case Asdf.Kind..string: 2661 { 2662 string str; 2663 if (auto exc = deserializeValue(data, str)) 2664 return exc; 2665 value = str; 2666 return null; 2667 } 2668 } 2669 2670 static if (contains!long || contains!double) 2671 { 2672 case Asdf.Kind.number: 2673 { 2674 import mir.bignum.decimal; 2675 DecimalExponentKey key; 2676 Decimal!256 decimal = void; 2677 auto str = (()@trusted => cast(string) data.data[2 .. $])(); 2678 2679 enum bool allowSpecialValues = false; 2680 enum bool allowDotOnBounds = false; 2681 enum bool allowDExponent = false; 2682 enum bool allowStartingPlus = false; 2683 enum bool allowUnderscores = false; 2684 enum bool allowLeadingZeros = false; 2685 enum bool allowExponent = true; 2686 enum bool checkEmpty = false; 2687 2688 if (!decimal.fromStringImpl!( 2689 char, 2690 allowSpecialValues, 2691 allowDotOnBounds, 2692 allowDExponent, 2693 allowStartingPlus, 2694 allowUnderscores, 2695 allowLeadingZeros, 2696 allowExponent, 2697 checkEmpty, 2698 )(str, key)) 2699 return new SerdeException("Asdf: can't parse number string: " ~ str); 2700 2701 if (key || !contains!long) 2702 { 2703 static if (contains!double) 2704 { 2705 value = cast(double) decimal; 2706 return null; 2707 } 2708 else 2709 { 2710 return new SerdeException("Asdf: can't parse integer string: " ~ str); 2711 } 2712 } 2713 static if (contains!long) 2714 { 2715 auto bigintView = decimal.coefficient.view; 2716 auto ret = cast(long) bigintView; 2717 if (ret != bigintView) { 2718 return new SerdeException("Asdf: integer overflow"); 2719 } 2720 value = ret; 2721 } 2722 return null; 2723 } 2724 } 2725 2726 static if (anySatisfy!(templateAnd!(isArray, templateNot!isSomeString), Types)) 2727 { 2728 case Asdf.Kind.array: 2729 { 2730 alias ArrayTypes = Filter!(templateAnd!(isArray, templateNot!isSomeString), Types); 2731 static assert(ArrayTypes.length == 1, ArrayTypes.stringof); 2732 ArrayTypes[0] array; 2733 if (auto exc = deserializeValue(data, array)) 2734 return exc; 2735 value = array; 2736 return null; 2737 } 2738 } 2739 2740 static if (anySatisfy!(isStringMap, Types)) 2741 { 2742 case Asdf.Kind.object: 2743 { 2744 alias MapTypes = Filter!(isStringMap, Types); 2745 static assert(MapTypes.length == 1, MapTypes.stringof); 2746 MapTypes[0] object; 2747 if (auto exc = deserializeValue(data, object)) 2748 return exc; 2749 value = object; 2750 return null; 2751 } 2752 } 2753 else 2754 static if (anySatisfy!(isAssociativeArray, Types)) 2755 { 2756 case Asdf.Kind.object: 2757 { 2758 alias AATypes = Filter!(isAssociativeArray, Types); 2759 static assert(AATypes.length == 1, AATypes.stringof); 2760 AATypes[0] object; 2761 if (auto exc = deserializeValue(data, object)) 2762 return exc; 2763 value = object; 2764 return null; 2765 } 2766 } 2767 2768 default: 2769 return unexpectedKind(data.kind); 2770 } 2771 } 2772 else 2773 static if (is(V == BigInt)) 2774 { 2775 if (data.kind != Asdf.Kind.number) 2776 return unexpectedKind(data.kind); 2777 value = BigInt((()@trusted => cast(string) data.data[2 .. $])()); 2778 return null; 2779 } 2780 else 2781 static if (isStdNullable!V) 2782 { 2783 if (data.kind == Asdf.Kind.null_) 2784 { 2785 value.nullify; 2786 return null; 2787 } 2788 2789 typeof(value.get) payload; 2790 if (auto exc = .deserializeValue(data, payload)) 2791 return exc; 2792 value = payload; 2793 return null; 2794 } 2795 else 2796 static if (__traits(hasMember, value, "deserializeFromAsdf")) 2797 { 2798 return __traits(getMember, value, "deserializeFromAsdf")(data); 2799 } 2800 else 2801 static if (hasUDA!(V, serdeProxy)) 2802 {{ 2803 serdeGetProxy!V proxy; 2804 enum S = hasUDA!(value, serdeScoped) && __traits(compiles, .deserializeScopedString(data, proxy)); 2805 alias Fun = Select!(S, .deserializeScopedString, .deserializeValue); 2806 if (auto exc = Fun(data, proxy)) 2807 return exc; 2808 value = proxy.to!V; 2809 return null; 2810 }} 2811 else 2812 { 2813 if (!(data.kind == Asdf.Kind.object)) 2814 { 2815 static if(__traits(compiles, value = null)) 2816 { 2817 if (data.kind == Asdf.Kind.null_) 2818 { 2819 value = null; 2820 return null; 2821 } 2822 } 2823 return unexpectedKind!("Cann't deserialize " ~ V.stringof ~ ". Unexpected data:")(data.kind); 2824 } 2825 2826 static if(is(V == class) || is(V == interface)) 2827 { 2828 if(value is null) 2829 { 2830 static if(__traits(compiles, value = new V)) 2831 { 2832 value = new V; 2833 } 2834 else 2835 { 2836 return unexpectedKind(data.kind, "Object / interface must be either not null or have a a default constructor."); 2837 } 2838 } 2839 } 2840 2841 SerdeFlags!V requiredFlags; 2842 2843 static if (hasUDA!(V, serdeOrderedIn)) 2844 { 2845 SerdeOrderedDummy!V temporal; 2846 if (auto exc = .deserializeValue(data, temporal)) 2847 return exc; 2848 temporal.serdeFinalizeTarget(value, requiredFlags); 2849 } 2850 else 2851 { 2852 import std.meta: aliasSeqOf; 2853 2854 alias impl = deserializeValueMemberImpl!(deserializeValue, deserializeScopedString); 2855 2856 static immutable exc(string member) = new SerdeException("ASDF deserialisation: non-optional member '" ~ member ~ "' in " ~ V.stringof ~ " is missing."); 2857 2858 static if (hasUDA!(V, serdeRealOrderedIn)) 2859 { 2860 static foreach(member; serdeFinalProxyDeserializableMembers!V) 2861 {{ 2862 enum keys = serdeGetKeysIn!(__traits(getMember, value, member)); 2863 static if (keys.length) 2864 { 2865 foreach(elem; data.byKeyValue) 2866 { 2867 switch(elem.key) 2868 { 2869 static foreach (key; keys) 2870 { 2871 case key: 2872 } 2873 if (auto mexp = impl!member(elem.value, value, requiredFlags)) 2874 return mexp; 2875 break; 2876 default: 2877 } 2878 } 2879 } 2880 2881 static if (!hasUDA!(__traits(getMember, value, member), serdeOptional)) 2882 if (!__traits(getMember, requiredFlags, member)) 2883 return exc!member; 2884 }} 2885 } 2886 else 2887 { 2888 foreach(elem; data.byKeyValue) 2889 { 2890 S: switch(elem.key) 2891 { 2892 static foreach(member; serdeFinalProxyDeserializableMembers!V) 2893 {{ 2894 enum keys = serdeGetKeysIn!(__traits(getMember, value, member)); 2895 static if (keys.length) 2896 { 2897 static foreach (key; keys) 2898 { 2899 case key: 2900 } 2901 if (auto mexp = impl!member(elem.value, value, requiredFlags)) 2902 return mexp; 2903 break S; 2904 } 2905 }} 2906 default: 2907 } 2908 } 2909 2910 static foreach(member; __traits(allMembers, SerdeFlags!V)) 2911 static if (!hasUDA!(__traits(getMember, value, member), serdeOptional)) 2912 if (!__traits(getMember, requiredFlags, member)) 2913 return exc!member; 2914 } 2915 } 2916 2917 static if(__traits(hasMember, V, "finalizeDeserialization")) 2918 { 2919 value.finalizeDeserialization(data); 2920 } 2921 static if(__traits(hasMember, V, "serdeFinalizeWithFlags")) 2922 { 2923 value.serdeFinalizeWithFlags(requiredFlags); 2924 } 2925 static if(__traits(hasMember, V, "serdeFinalize")) 2926 { 2927 value.serdeFinalize(); 2928 } 2929 return null; 2930 } 2931 } 2932 2933 /// StringMap support 2934 unittest 2935 { 2936 import mir.string_map; 2937 auto map = `{"b" : 1.0, "a" : 2}`.deserialize!(StringMap!double); 2938 assert(map.keys == ["b", "a"]); 2939 assert(map.values == [1.0, 2.0]); 2940 assert(map.serializeToJson == `{"b":1.0,"a":2.0}`); 2941 2942 } 2943 2944 /// JsonAlgebraic alias support 2945 unittest 2946 { 2947 import mir.algebraic_alias.json; 2948 auto value = `{"b" : 1.0, "a" : [1, true, false, null, "str"]}`.deserialize!JsonAlgebraic; 2949 assert(value.kind == JsonAlgebraic.Kind.object); 2950 2951 auto object = value.get!(StringMap!JsonAlgebraic); 2952 assert(object.keys == ["b", "a"]); // sequental order 2953 assert(object["b"].get!double == 1.0); 2954 object["b"].get!double += 4; 2955 2956 auto array = object["a"].get!(JsonAlgebraic[]); 2957 assert(array[0].get!long == 1); 2958 array[0].get!long += 10; 2959 assert(array[1].get!bool == true); 2960 assert(array[2].get!bool == false); 2961 assert(array[3].isNull); 2962 assert(array[3].get!(typeof(null)) is null); 2963 assert(array[4].get!string == "str"); 2964 2965 assert(value.serializeToJson == `{"b":5.0,"a":[11,true,false,null,"str"]}`); 2966 value = [JsonAlgebraic[].init.JsonAlgebraic, StringMap!JsonAlgebraic.init.JsonAlgebraic, string.init.JsonAlgebraic]; 2967 // algebraics have type safe serialization instead of null values 2968 assert(value.serializeToJson == `[[],{},""]`, value.serializeToJson); 2969 } 2970 2971 /++ 2972 User defined algebraic types deserialization supports any subset of the following types: 2973 2974 $(UL 2975 $(LI `typeof(null)`) 2976 $(LI `bool`) 2977 $(LI `long`) 2978 $(LI `double`) 2979 $(LI `string`) 2980 $(LI `AnyType[]`) 2981 $(LI `StringMap!AnyType`) 2982 $(LI `AnyType[string]`) 2983 ) 2984 2985 A `StringMap` has has priority over builtin associative arrays. 2986 2987 Serializations works with any algebraic types. 2988 2989 See_also: $(GMREF mir-core, mir,algebraic), $(GMREF mir-algorithm, mir,string_map) 2990 +/ 2991 unittest 2992 { 2993 import mir.algebraic: Nullable, This; // Nullable, Variant, or TaggedVariant 2994 alias MyJsonAlgebraic = Nullable!(bool, string, double[], This[string]); 2995 2996 auto value = `{"b" : true, "z" : null, "this" : {"c" : "str", "d" : [1, 2, 3, 4]}}`.deserialize!MyJsonAlgebraic; 2997 2998 auto object = value.get!(MyJsonAlgebraic[string]); 2999 assert(object["b"].get!bool == true); 3000 assert(object["z"].isNull); 3001 3002 object = object["this"].get!(MyJsonAlgebraic[string]); 3003 assert(object["c"].get!string == "str"); 3004 assert(object["d"].get!(double[]) == [1.0, 2, 3, 4]); 3005 } 3006 3007 /// 3008 unittest 3009 { 3010 static class Turtle 3011 { 3012 string _metadata; 3013 long id; 3014 string species; 3015 } 3016 3017 auto turtles = ` 3018 [{"_metadata":"xyz123", "id":72, "species":"Galapagos"}, 3019 {"_metadata":"tu144", "id":108, "species":"Snapping"}, 3020 null, 3021 null, 3022 {"_metadata":"anew1", "id":9314, "species":"Sea Turtle"}]` 3023 .deserialize!(Turtle[]); 3024 } 3025 3026 /// Alias this support 3027 unittest 3028 { 3029 struct S 3030 { 3031 int a; 3032 } 3033 3034 struct C 3035 { 3036 S s; 3037 alias s this; 3038 int b; 3039 } 3040 3041 assert(`{"a":3, "b":4}`.deserialize!C == C(S(3), 4)); 3042 } 3043 3044 3045 /// `serdeOrderedIn` supprot 3046 unittest 3047 { 3048 static struct I 3049 { 3050 @serdeOptional 3051 int a; 3052 int m; 3053 } 3054 3055 @serdeOrderedIn 3056 static struct S 3057 { 3058 import mir.small_string; 3059 3060 SmallString!8 id; 3061 3062 int acc; 3063 3064 I inner = I(1000, 0); 3065 3066 @safe pure nothrow @nogc 3067 @property: 3068 3069 void add(int v) 3070 { 3071 inner.a += v; 3072 acc += v; 3073 } 3074 3075 void mul(int v) 3076 { 3077 inner.m += v; 3078 acc *= v; 3079 } 3080 } 3081 3082 import mir.reflection; 3083 3084 auto val = `{"mul":2, "id": "str", "add":5,"acc":100, "inner":{"m": 2000}}`.deserialize!S; 3085 assert(val.id == "str"); 3086 assert(val.acc == 210); 3087 assert(val.inner.a == 1005); 3088 assert(val.inner.m == 2002); 3089 assert(val.serializeToJson == `{"id":"str","acc":210,"inner":{"a":1005,"m":2002}}`); 3090 } 3091 3092 /// `serdeRealOrderedIn` supprot 3093 unittest 3094 { 3095 static struct I 3096 { 3097 @serdeOptional 3098 int a; 3099 int m; 3100 } 3101 3102 @serdeRealOrderedIn 3103 static struct S 3104 { 3105 import mir.small_string; 3106 3107 SmallString!8 id; 3108 3109 int acc; 3110 3111 I inner = I(1000, 0); 3112 3113 @safe pure nothrow @nogc 3114 @property: 3115 3116 void add(int v) 3117 { 3118 inner.a += v; 3119 acc += v; 3120 } 3121 3122 void mul(int v) 3123 { 3124 inner.m += v; 3125 acc *= v; 3126 } 3127 } 3128 3129 import mir.reflection; 3130 3131 auto val = `{"mul":2, "id": "str", "add":5,"acc":100, "inner":{"m": 2000}}`.deserialize!S; 3132 assert(val.id == "str"); 3133 assert(val.acc == 210); 3134 assert(val.inner.a == 1005); 3135 assert(val.inner.m == 2002); 3136 assert(val.serializeToJson == `{"id":"str","acc":210,"inner":{"a":1005,"m":2002}}`); 3137 } 3138 3139 /// 3140 unittest 3141 { 3142 struct A { 3143 string str; 3144 } 3145 struct B { 3146 A a; 3147 string serialize() const { 3148 return asdf.serializeToJson(a); 3149 } 3150 } 3151 assert(B(A("2323")).serialize == `{"str":"2323"}`); 3152 } 3153 3154 private template isNullable(T) 3155 { 3156 import std.traits : hasMember; 3157 3158 static if ( 3159 hasMember!(T, "isNull") && 3160 is(typeof(__traits(getMember, T, "isNull")) == bool) && 3161 hasMember!(T, "get") && 3162 !is(typeof(__traits(getMember, T, "get")) == void) && 3163 hasMember!(T, "nullify") && 3164 is(typeof(__traits(getMember, T, "nullify")) == void) 3165 ) 3166 { 3167 enum isNullable = true; 3168 } 3169 else 3170 { 3171 enum isNullable = false; 3172 } 3173 } 3174 3175 deprecated("use @serdeIgnoreOut instead") 3176 alias serializationIgnoreOut = serdeIgnoreOut; 3177 3178 deprecated("use @serdeIgnoreIn instead") 3179 alias serializationIgnoreIn = serdeIgnoreIn; 3180 3181 deprecated("use @serdeIgnore instead") 3182 alias serializationIgnore = serdeIgnore; 3183 3184 deprecated("use @serdeKeys instead") 3185 alias serializationKeys = serdeKeys; 3186 3187 deprecated("use @serdeKeys instead") 3188 alias serializationKeyOut = serdeKeyOut; 3189 3190 deprecated("use @serdeIgnoreDefault instead") 3191 alias serializationIgnoreDefault = serdeIgnoreDefault; 3192 3193 deprecated("use @serdeLikeList instead") 3194 alias serializationLikeArray = serdeLikeList; 3195 3196 deprecated("use @serdeLikeStruct instead") 3197 alias serializationLikeObject = serdeLikeStruct; 3198 3199 deprecated("use @serdeProxy instead") 3200 alias serializedAs = serdeProxy; 3201 3202 deprecated("use @serdeIgnoreOutIf instead") 3203 alias serializationIgnoreOutIf = serdeIgnoreOutIf; 3204 3205 deprecated("use @serdeTransformIn instead") 3206 alias serializationTransformIn = serdeTransformIn; 3207 3208 deprecated("use @serdeTransformOut instead") 3209 alias serializationTransformOut = serdeTransformOut; 3210 3211 deprecated("use @serdeScoped instead") 3212 alias serializationScoped = serdeScoped;