1 /** 2 * Serialization from a D variable. 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <vladimir@thecybershadow.net> 12 */ 13 14 module ae.utils.sd.serialization.serializer; 15 16 import std.traits; 17 18 import ae.utils.text : fpAsString; 19 import ae.utils.text.ascii : decimalSize, toDec; 20 21 /// Serialization source which serializes a given object. 22 struct Serializer(T) 23 { 24 T* object; 25 26 auto read(Handler)(Handler handler) 27 { 28 static if (__traits(hasMember, Handler, q{canHandleValue}) 29 && Handler.canHandleValue!(typeof(null)) 30 && is(typeof(*object is null))) 31 { 32 if (*object is null) 33 return handler.handleValue(null); 34 } 35 36 static if (__traits(hasMember, Handler, q{canHandleValue}) && Handler.canHandleValue!T) 37 return handler.handleValue(*object); 38 else 39 static if (__traits(hasMember, Handler, q{canHandleTypeHint}) && Handler.canHandleTypeHint!T) 40 return handler.handleTypeHint!T(this); 41 else 42 static if (isNumeric!T && __traits(hasMember, Handler, q{handleNumeric})) 43 return handler.handleNumeric(NumericReader(object)); 44 else 45 static if (is(T == struct)) 46 return handler.handleMap(StructReader(object)); 47 else 48 static if (is(T V : V[K], K)) 49 return handler.handleMap(AAReader(object)); 50 else 51 static if (is(T U : U[])) 52 return handler.handleArray(ArrayReader(object)); 53 else 54 static assert(false, "Sink handler " ~ Handler.stringof ~ " can't accept values of type " ~ T.stringof); 55 } 56 57 static if (isIntegral!T) 58 struct NumericReader 59 { 60 T* object; 61 62 auto read(Handler)(Handler handler) 63 { 64 char[decimalSize!T] buf = void; 65 return handler.handleSlice!char(toDec(*object, buf)); 66 } 67 } 68 69 static if (isFloatingPoint!T) 70 struct NumericReader 71 { 72 T* object; 73 74 auto read(Handler)(Handler handler) 75 { 76 auto s = fpAsString(*object); 77 return handler.handleSlice!char(s.buf.data); 78 } 79 } 80 81 struct ArrayReader 82 { 83 T* object; 84 85 auto read(Handler)(Handler handler) 86 { 87 alias E = typeof((*object)[0]); 88 89 static if (__traits(hasMember, Handler, q{canHandleSlice}) && Handler.canHandleSlice!T) 90 handler.handleSlice(*object); 91 else 92 foreach (ref c; *object) 93 handler.handleElement(Serializer!E(&c)); 94 return handler.handleEnd(); 95 } 96 } 97 98 struct AAReader 99 { 100 T* object; 101 102 auto read(Handler)(Handler handler) 103 { 104 alias K = typeof((*object).keys[0]); 105 alias V = typeof((*object).values[0]); 106 alias Pair = typeof((*object).byKeyValue.front); 107 108 struct PairReader 109 { 110 Pair* pair; 111 112 auto read(Handler)(Handler handler) 113 { 114 handler.handlePairKey(Serializer!K(&pair.key())); 115 handler.handlePairValue(Serializer!V(&pair.value())); 116 return handler.handleEnd(); 117 } 118 } 119 120 foreach (ref pair; object.byKeyValue()) 121 handler.handlePair(PairReader(&pair)); 122 return handler.handleEnd(); 123 } 124 } 125 126 struct StructReader 127 { 128 T* object; 129 130 auto read(Handler)(Handler handler) 131 { 132 struct FieldReader(size_t fieldIndex) 133 { 134 T* object; 135 136 auto read(Handler)(Handler handler) 137 { 138 static immutable name = __traits(identifier, T.tupleof[fieldIndex]); 139 handler.handlePairKey(Serializer!(immutable(string))(&name)); 140 141 alias F = typeof(object.tupleof[fieldIndex]); 142 handler.handlePairValue(Serializer!F(&object.tupleof[fieldIndex])); 143 144 return handler.handleEnd(); 145 } 146 } 147 148 static foreach (fieldIndex; 0 .. T.tupleof.length) 149 handler.handlePair(FieldReader!fieldIndex(object)); 150 return handler.handleEnd(); 151 } 152 } 153 154 static template Impl(alias anchor) 155 { 156 static void read(Sink, T)(Sink sink, auto ref T v) 157 { 158 static if (is(typeof(v is null))) 159 if (v is null) 160 { 161 sink.handleNull(); 162 return; 163 } 164 165 static if (is(T == bool)) 166 sink.handleBoolean(v); 167 else 168 static if (is(T : ulong)) 169 { 170 char[decimalSize!T] buf = void; 171 sink.handleNumeric(toDec(v, buf)); 172 } 173 else 174 static if (isNumeric!T) // floating point 175 { 176 import ae.utils.textout; 177 178 static char[64] arr; 179 auto buf = StringBuffer(arr); 180 formattedWrite(&buf, "%s", v); 181 sink.handleNumeric(buf.get()); 182 } 183 else 184 static if (is(T == struct)) 185 { 186 auto reader = StructReader!T(v.reference); 187 sink.handleObject(boundFunctorOf!(StructReader!T.read)(&reader)); 188 } 189 else 190 static if (is(T V : V[K], K)) 191 { 192 alias Reader = AAReader!(T, K, V); 193 auto reader = Reader(v); 194 sink.handleObject(boundFunctorOf!(Reader.read)(&reader)); 195 } 196 else 197 static if (is(T : string)) 198 sink.handleString(v); 199 else 200 static if (is(T U : U[])) 201 { 202 alias Reader = ArrayReader!T; 203 auto reader = Reader(v); 204 sink.handleArray(boundFunctorOf!(Reader.readArray)(&reader)); 205 } 206 else 207 static assert(false, "Don't know how to serialize " ~ T.stringof); 208 } 209 210 static struct StructReader(T) 211 { 212 RefType!T p; 213 void read(Sink)(Sink sink) 214 { 215 foreach (i, ref field; p.dereference.tupleof) 216 { 217 import std.array : split; 218 enum name = p.dereference.tupleof[i].stringof.split(".")[$-1]; 219 220 alias ValueReader = Reader!(typeof(field)); 221 auto reader = ValueReader(&field); 222 sink.handleField(unboundFunctorOf!(stringReader!name), boundFunctorOf!(ValueReader.readValue)(&reader)); 223 } 224 } 225 } 226 227 static struct AAReader(T, K, V) 228 { 229 T aa; 230 void read(Sink)(Sink sink) 231 { 232 foreach (K k, ref V v; aa) 233 { 234 alias KeyReader = Reader!K; 235 auto keyReader = KeyReader (&k); 236 alias ValueReader = Reader!V; 237 auto valueReader = ValueReader(&v); 238 sink.handleField( 239 boundFunctorOf!(KeyReader .readValue)(&keyReader ), 240 boundFunctorOf!(ValueReader.readValue)(&valueReader), 241 ); 242 } 243 } 244 } 245 246 static struct ArrayReader(T) 247 { 248 T arr; 249 void readArray(Sink)(Sink sink) 250 { 251 foreach (ref v; arr) 252 read(sink, v); 253 } 254 } 255 256 static template stringReader(string name) 257 { 258 static void stringReader(Sink)(Sink sink) 259 { 260 sink.handleString(name); 261 } 262 } 263 264 static struct Reader(T) 265 { 266 T* p; 267 268 void readValue(Sink)(Sink sink) 269 { 270 read(sink, *p); 271 } 272 } 273 } 274 } 275 276 Serializer!T serialize(T)(ref T object) 277 { 278 return Serializer!T(&object); 279 }