1 2 // Copyright Luna & Cospec 2019. 3 // Distributed under the Boost Software License, Version 1.0. 4 // (See accompanying file LICENSE_1_0.txt or copy at 5 // https://www.boost.org/LICENSE_1_0.txt) 6 7 module wsf.serialization.deserializer; 8 import wsf.serialization; 9 import wsf.ast; 10 import std.traits; 11 import std.format; 12 import std.range.primitives; 13 import std.stdio : writeln; 14 15 private { 16 /* 17 Creates empty class, struct or heap allocated struct 18 */ 19 T newEmptyT(T)() { 20 static if (isPointer!T) { 21 static assert(is(PointerTarget!T == struct), "Pointer did not point to a struct!"); 22 return new PointerTarget!T; 23 } else static if (is(T == class)) { 24 return new T(); 25 } else static if (is(T == struct)) { 26 return *(new T); 27 } else { 28 static assert(0, "Cannot create empty "~T.stringof); 29 } 30 } 31 32 void deserializeStructOrClass(T)(ref T object, ref Tag tag) { 33 static if (hasStaticMember!(T, "deserialize")) { 34 alias deserializerFunc = __traits(getMember, T, "deserialize"); 35 static if (is(Parameters!deserializerFunc[0] : T) && is(Parameters!deserializerFunc[1] == Tag)) { 36 T.deserialize(object, tag); 37 } else { 38 static assert(0, "Invalid deserialization function! "~typeof(serializerFunc).stringof); 39 } 40 } else { 41 foreach(memberName; FieldNameTuple!T) { 42 43 alias member = __traits(getMember, object, memberName); 44 enum protection = __traits(getProtection, member); 45 static if (!hasUDA!(member, ignore)) { 46 if (memberName !in tag) { 47 if (hasUDA!(member, optional)) continue; 48 else throw new Exception("Mandetory field "~memberName~" not present."); 49 } 50 51 // Handle sequences 52 static if (memberName == "seq") { 53 static if (is(member : Tag[])) { 54 __traits(getMember, object, memberName) = tag[memberName]; 55 } else { 56 if ("seq_" !in tag) throw new Exception("A seq_ tag could not be found!"); 57 deserializeArray!(typeof(member))(__traits(getMember, object, memberName), tag["seq_"]); 58 } 59 } else { 60 deserializeMember!(typeof(member))(__traits(getMember, object, memberName), tag[memberName]); 61 } 62 } 63 } 64 } 65 } 66 67 void deserializeAA(T)(ref T object, ref Tag tag) { 68 foreach(string key; tag.compound.keys) { 69 70 // Sequential keys cannot be fetched from simple associative arrays 71 if (key == "seq") continue; 72 if (key !in tag) continue; 73 if (tag.length == 0) continue; 74 object[key] = ValueType!T.init; 75 deserializeMember!(ValueType!T)(object[key], tag[key]); 76 } 77 } 78 79 void deserializeArray(T)(ref T object, ref Tag tag) { 80 static if (isDynamicArray!T) object.length = tag.length; 81 foreach(i; 0..object.length) { 82 if (tag is null) continue; 83 if (tag.length == 0) continue; 84 if (i > tag.length) return; 85 deserializeMember(object[i], tag[i]); 86 } 87 } 88 89 void deserializeMember(T)(ref T object, ref Tag tag) { 90 static if (is(T == class) || is(T == struct) || isPointer!T) { 91 deserializeStructOrClass(object, tag); 92 } else static if (isAssociativeArray!T && is(KeyType!T : string) && !is(object : Tag[string])) { 93 deserializeAA(object, tag); 94 } else static if (isArray!T && !is(T : string)) { 95 deserializeArray(object, tag); 96 } else static if (is(object : Tag)) { 97 object = tag; 98 } else static if (is(object : Tag[])) { 99 object = tag.array; 100 } else static if (is(object : Tag[string])) { 101 object = tag.compound; 102 } else { 103 object = tag.get!T; 104 } 105 } 106 } 107 108 /** 109 Deserialize from a WSF tag 110 */ 111 T deserializeWSF(T)(Tag tag) { 112 T val = newEmptyT!T; 113 deserializeMember!T(val, tag); 114 return val; 115 }