1 module telega.serialization;
2 
3 import std.traits;
4 import std.typecons;
5 import std.meta : AliasSeq, staticIndexOf;
6 import asdf;
7 
8 string serializeToJsonString(T)(T value)
9 {
10     import std.conv : to;
11 
12     Asdf asdf = serializeToAsdf(value);
13     removeNulledNodes(asdf);
14 
15     return  asdf.to!string;
16 }
17 
18 unittest
19 {
20     import std.typecons;
21 
22     alias FewTypes = AliasSeq!(int, string);
23 
24     struct S
25     {
26         JsonableAlgebraicProxy!FewTypes a;
27     }
28 
29     S s;
30     s.a = 42;
31 
32     assert(`{"a":42}` == s.serializeToJson());
33 
34     s.a = "123";
35     assert(`{"a":"123"}` == s.serializeToJson());
36 }
37 
38 void removeNulledNodes(ref Asdf a)
39 {
40     if (a.kind == Asdf.Kind.null_) {
41         a.remove();
42     } else if (a.kind == Asdf.Kind.array) {
43         foreach (v; a.byElement) {
44             removeNulledNodes(v);
45         }
46     } else if (a.kind == Asdf.Kind.object) {
47         foreach (kv; a.byKeyValue) {
48             removeNulledNodes(kv.value);
49         }
50     }
51 }
52 
53 unittest
54 {
55     import std.conv: to;
56 
57     string jsonWithNulls = `{
58         "chat_id":"100000001",
59         "text":"o",
60         "reply_markup":{
61             "keyboard":[
62                 [
63                     {"text":"First Button","request_contact":null,"request_location":null},
64                     {"text":"Second Button","request_contact":null,"request_location":null}
65                 ],
66                 [
67                     {"text":"Ask location","request_contact":false,"request_location":true}
68                 ],
69                 [
70                     {"text":"Remove Keyboard","request_contact":null,"request_location":null}
71                 ]
72             ],
73             "resize_keyboard":false,
74             "selective":false,
75             "one_time_keyboard":false
76         }
77     }`;
78     string cleanJson = `{
79         "chat_id":"100000001",
80         "text":"o",
81         "reply_markup":{
82             "keyboard":[
83                 [
84                     {"text":"First Button"},
85                     {"text":"Second Button"}
86                 ],
87                 [
88                     {"text":"Ask location","request_contact":false,"request_location":true}
89                 ],
90                 [
91                     {"text":"Remove Keyboard"}
92                 ]
93             ],
94             "resize_keyboard":false,
95             "selective":false,
96             "one_time_keyboard":false
97         }
98     }`;
99 
100     Asdf asdf = jsonWithNulls.parseJson();
101 
102     removeNulledNodes(asdf);
103 
104     assert(asdf.to!string == cleanJson.parseJson.to!string);
105 }
106 
107 struct JsonableAlgebraicProxy(Typelist ...)
108 {
109     import std.variant;
110     import asdf;
111 
112     private Algebraic!Typelist value;
113 
114     //alias value this;
115 
116     void opAssign(T)(T value)
117         if (staticIndexOf!(T, Typelist) >= 0)
118     {
119         this.value = value;
120     }
121 
122     static Algebraic!Typelist deserialize(Asdf data)
123     {
124         assert(false, "Deserialization of a value is not implemented.");
125     }
126 
127     void serialize(S)(ref S serializer)
128     {
129         if (!value.hasValue) {
130             serializer.putValue("{}");
131 
132             return;
133         }
134 
135         static foreach (T; Typelist) {
136             if (value.type == typeid(T)) {
137                 T result = cast(T)value.get!T;
138 
139                 serializer.serializeValue(result);
140             }
141         }
142     }
143 }