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 }