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