1 /** 2 * Intermediary, abstract format for serialization. 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 <ae@cy.md> 12 */ 13 14 deprecated module ae.utils.serialization.store; 15 deprecated: 16 17 import std.conv; 18 import std.exception; 19 import std.string; 20 import std.traits; 21 22 import ae.utils.meta; 23 24 /// A discriminated union type which can be used as both a serialization sink and source. 25 /// Similar to std.variant.Variant and std.json.JSONValue. 26 struct SerializedObject(C) 27 { 28 alias S = C[]; 29 30 enum Type 31 { 32 sNone, 33 sNumeric, 34 sString, 35 sStringFragments, 36 sNull, 37 sBoolean, 38 sArray, 39 sObject, 40 } 41 42 Type type; 43 44 union 45 { 46 S sNumeric; 47 S sString; 48 S[] sStringFragments; 49 bool sBoolean; 50 SerializedObject[] sArray; 51 SerializedObject[S] sObject; 52 } 53 54 // *********************************************************************** 55 56 this(T)(T v) 57 if (is(typeof(this = v))) 58 { 59 this = v; 60 } 61 62 void opAssign(T)(T v) 63 if (is(isNumeric!T)) 64 { 65 type = Type.sNumeric; 66 sNumeric = v.numberToString.to!S; 67 } 68 69 void opAssign(T)(T v) 70 if (isSomeString!T) 71 { 72 type = Type.sString; 73 sString = v.to!S; 74 } 75 76 void opAssign(T)(T v) 77 if (is(T == typeof(null))) 78 { 79 assert(v is null); 80 type = Type.sNull; 81 } 82 83 void opAssign(T)(T v) 84 if (is(T == bool)) 85 { 86 type = Type.sBoolean; 87 sBoolean = v; 88 } 89 90 void opAssign(T)(T v) 91 if (is(T U : U[]) && !isSomeString!T) 92 { 93 type = Type.sArray; 94 import std.range, std.array; 95 sArray = v.map!(e => SerializedObject!C(e)).array; 96 } 97 98 void opAssign(T)(T aa) 99 if (is(T K : V[K], V) && isSomeString!K) 100 { 101 type = Type.sObject; 102 sObject = null; 103 foreach (k, ref v; aa) 104 sObject[k.to!S] = SerializedObject!C(v); 105 } 106 107 ref SerializedObject opIndex(size_t i) 108 { 109 enforce(type == Type.sArray, "SerializedObject is %s, not sArray".format(type)); 110 enforce(i < sArray.length, "SerializedObject sArray index %d out of bounds (0..%d)".format(i, sArray.length)); 111 return sArray[i]; 112 } 113 114 ref SerializedObject opIndex(S s) 115 { 116 enforce(type == Type.sObject, "SerializedObject is %s, not sObject".format(type)); 117 return sObject[s]; 118 } 119 120 // *********************************************************************** 121 122 enum isSerializationSink = true; 123 124 void handleNumeric(CC)(CC[] s) 125 { 126 assert(type == Type.sNone); 127 type = Type.sNumeric; 128 sNumeric = s.to!S; 129 } 130 131 void handleString(CC)(CC[] s) 132 { 133 assert(type == Type.sNone); 134 type = Type.sString; 135 sString = s.to!S; 136 } 137 138 void handleStringFragments(Reader)(Reader reader) 139 { 140 static struct StringFragmentSink 141 { 142 S[]* arr; 143 144 void handleStringFragment(CC)(CC[] s) 145 { 146 *arr ~= s.to!S; 147 } 148 } 149 150 assert(type == Type.sNone); 151 type = Type.sStringFragments; 152 reader(StringFragmentSink(&sStringFragments)); 153 } 154 155 void handleNull() 156 { 157 assert(type == Type.sNone); 158 type = Type.sNull; 159 } 160 161 void handleBoolean(bool value) 162 { 163 assert(type == Type.sNone); 164 type = Type.sBoolean; 165 sBoolean = value; 166 } 167 168 void handleArray(Reader)(Reader reader) 169 { 170 static struct ArraySink 171 { 172 SerializedObject[]* arr; 173 174 alias handleStringFragments = opDispatch!"handleStringFragments"; 175 alias handleObject = opDispatch!"handleObject"; 176 177 template opDispatch(string name) 178 { 179 void opDispatch(Args...)(auto ref Args args) 180 { 181 SerializedObject obj; 182 mixin("obj." ~ name ~ "(args);"); 183 *arr ~= obj; 184 } 185 } 186 } 187 188 assert(type == Type.sNone); 189 type = Type.sArray; 190 reader(ArraySink(&sArray)); 191 } 192 193 void handleObject(Reader)(Reader reader) 194 { 195 static struct ObjectSink 196 { 197 SerializedObject[S]* aa; 198 199 void handleField(NameReader, ValueReader)(NameReader nameReader, ValueReader valueReader) 200 { 201 static struct StringSink 202 { 203 S s; 204 void handleString(CC)(CC[] s) 205 { 206 this.s = s.to!S; 207 } 208 209 void handleStringFragments(Reader)(Reader reader) 210 { 211 reader(&this); 212 } 213 214 void handleStringFragment(CC)(CC[] fragment) 215 { 216 s ~= fragment.to!S; 217 } 218 219 void bad() { throw new Exception("String expected"); } 220 221 void handleNumeric(CC)(CC[] s) { bad(); } 222 void handleNull() { bad(); } 223 void handleBoolean(bool value) { bad(); } 224 void handleArray(Reader)(Reader reader) { bad(); } 225 void handleObject(Reader)(Reader reader) { bad(); } 226 } 227 228 StringSink nameSink; 229 nameReader(nameSink); 230 SerializedObject value; 231 valueReader(&value); 232 (*aa)[nameSink.s] = value; 233 } 234 } 235 236 assert(type == Type.sNone); 237 type = Type.sObject; 238 reader(ObjectSink(&sObject)); 239 } 240 241 auto traverse(CC, Reader)(in CC[] name, Reader reader) 242 { 243 if (type == Type.sNone) 244 { 245 type = Type.sObject; 246 sObject = null; 247 } 248 enforce(type == Type.sObject, "Can't traverse %s".format(type)); 249 250 auto pv = name in sObject; 251 if (!pv) 252 { 253 *p[name] = SerializedObject.init; 254 pv = name in *p; 255 } 256 return reader(pv); 257 } 258 259 // *********************************************************************** 260 261 void read(Sink)(Sink sink) 262 { 263 final switch (type) 264 { 265 case Type.sNone: 266 assert(false, "Uninitialized SerializedObject"); 267 case Type.sNumeric: 268 sink.handleNumeric(sNumeric); 269 break; 270 case Type.sString: 271 sink.handleString(sString); 272 break; 273 case Type.sStringFragments: 274 sink.handleStringFragments(boundFunctorOf!readStringFragments(&this)); 275 break; 276 case Type.sNull: 277 sink.handleNull(); 278 break; 279 case Type.sBoolean: 280 sink.handleBoolean(sBoolean); 281 break; 282 case Type.sArray: 283 sink.handleArray(boundFunctorOf!readArray(&this)); 284 break; 285 case Type.sObject: 286 sink.handleObject(boundFunctorOf!readObject(&this)); 287 break; 288 } 289 } 290 291 void readStringFragments(Sink)(Sink sink) 292 { 293 assert(type == Type.sStringFragments); 294 foreach (fragment; sStringFragments) 295 sink.handleStringFragment(fragment); 296 } 297 298 void readArray(Sink)(Sink sink) 299 { 300 assert(type == Type.sArray); 301 foreach (el; sArray) 302 el.read(sink); 303 } 304 305 struct StringReader 306 { 307 S s; 308 this(S s) { this.s = s; } 309 void opCall(Sink)(Sink sink) 310 { 311 sink.handleString(s); 312 } 313 } 314 315 void readObject(Sink)(Sink sink) 316 { 317 assert(type == Type.sObject); 318 foreach (name, ref value; sObject) 319 sink.handleField(StringReader(name), boundFunctorOf!read(&value)); 320 } 321 } 322 323 unittest 324 { 325 SerializedObject!(immutable(char)) s1, s2; 326 s1 = "aoeu"; 327 s1.read(&s2); 328 } 329 330 unittest 331 { 332 import ae.utils.serialization.json; 333 auto s = jsonParse!(SerializedObject!(immutable(char)))(`null`); 334 assert(s.type == s.Type.sNull); 335 }