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;