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 }