1 module yamlserialized.deserialization; 2 3 import std.conv; 4 import std.traits; 5 6 import dyaml; 7 8 void deserializeInto(T)(Node yamlNode, ref T array) if (isArray!T) { 9 alias ElementType = ForeachType!T; 10 11 // Iterate each item in the array of nodes and add them to values, converting them to the actual type 12 foreach(item; yamlNode.as!(Node[])) { 13 static if (is(ElementType == struct)) { 14 // This item is a struct - instantiate it 15 ElementType newStruct; 16 17 // ...deserialize into the new instance 18 item.deserializeInto(newStruct); 19 20 // ...and add it to the array 21 array ~= newStruct; 22 } 23 else static if (is(ElementType == class)) { 24 // The item type is class - create a new instance 25 auto newClass = new ElementType(); 26 27 // ...deserialize into the new instance 28 item.deserializeInto(newClass); 29 30 // ...and add it to the array 31 array ~= newClass; 32 } 33 else static if (isSomeString!ElementType) { 34 array ~= item.as!string.to!ElementType; 35 } 36 else static if (isArray!ElementType) { 37 // An array of arrays. Recursion time! 38 ElementType subArray; 39 40 item.deserializeInto(subArray); 41 array ~= subArray; 42 } 43 else { 44 array ~= item.as!ElementType; 45 } 46 } 47 } 48 49 void deserializeInto(T)(Node yamlNode, ref T associativeArray) if (isAssociativeArray!T) { 50 alias VType = ValueType!T; 51 52 // Iterate each Pair in the Node 53 foreach(pair; yamlNode.as!(Node.Pair[])) { 54 auto key = pair.key.as!string.to!(KeyType!T); 55 auto value = pair.value; 56 57 static if (isAssociativeArray!VType) { 58 /* The associative array's value type is another associative array type. 59 It's recursion time. */ 60 61 if (key in associativeArray) { 62 value.deserializeInto(associativeArray[key]); 63 } 64 else { 65 VType subAssocArray; 66 67 value.deserializeInto(subAssocArray); 68 associativeArray[key] = subAssocArray; 69 } 70 } 71 else static if (is(VType == struct)) { 72 // The value type is a struct - instantiate it 73 VType newStruct; 74 75 // ...deserialize into the new instance 76 value.deserializeInto(newStruct); 77 78 // ...and add it to the associative array 79 associativeArray[key] = newStruct; 80 } 81 else static if (is(VType == class)) { 82 // The value type is class - create a new instance 83 auto newClass = new VType(); 84 85 // ...deserialize into the new instance 86 value.deserializeInto(newClass); 87 88 // ...and add it to the associative array 89 associativeArray[key] = newClass; 90 } 91 else { 92 associativeArray[key] = value.as!VType; 93 } 94 } 95 } 96 97 void deserializeInto(T)(Node yamlNode, ref T obj) if (is(T == struct) || is(T == class)) { 98 enum fieldNames = FieldNameTuple!T; 99 100 foreach(fieldName; fieldNames) { 101 alias FieldType = typeof(__traits(getMember, obj, fieldName)); 102 103 if (!yamlNode.containsKey(fieldName)) { 104 continue; 105 } 106 107 static if (is(FieldType == struct)) { 108 // This field is a struct - recurse into it 109 yamlNode[fieldName].deserializeInto(__traits(getMember, obj, fieldName)); 110 } 111 else static if (is(FieldType == class)) { 112 // This field is a class - recurse into it unless it is null 113 if (__traits(getMember, obj, fieldName) !is null) { 114 yamlNode[fieldName].deserializeInto(__traits(getMember, obj, fieldName)); 115 } 116 } 117 else static if (isSomeChar!FieldType) { 118 // Field is a char 119 /* Node.as!char fails for some reason, so we have to retrieve it as a string first 120 and then convert it to the correct type. */ 121 __traits(getMember, obj, fieldName) = yamlNode[fieldName].as!string.to!FieldType; 122 } 123 else static if (isSomeString!FieldType) { 124 // Field is a string 125 __traits(getMember, obj, fieldName) = yamlNode[fieldName].as!FieldType; 126 } 127 else static if (isArray!FieldType) { 128 // Field is an array 129 yamlNode[fieldName].deserializeInto(__traits(getMember, obj, fieldName)); 130 } 131 else static if (isAssociativeArray!FieldType) { 132 // Field is an associative array 133 yamlNode[fieldName].deserializeInto(__traits(getMember, obj, fieldName)); 134 } 135 else static if (isIntegral!FieldType) { 136 // Field is an integer 137 if (yamlNode[fieldName].isInt) { 138 // If node contains an integer value, get it directly 139 __traits(getMember, obj, fieldName) = yamlNode[fieldName].as!FieldType; 140 } 141 else { 142 // If node contains a non-integer value, convert it to a string first and then to the correct type 143 __traits(getMember, obj, fieldName) = yamlNode[fieldName].as!string.to!FieldType; 144 } 145 } 146 else static if (isBoolean!FieldType) { 147 /* Convert to string first, then to the correct boolean type. */ 148 __traits(getMember, obj, fieldName) = yamlNode[fieldName].as!string.to!FieldType; 149 } 150 else { 151 __traits(getMember, obj, fieldName) = yamlNode[fieldName].as!FieldType; 152 } 153 } 154 } 155 156 T deserializeTo(T)(Node yamlNode) if (is(T == struct)) { 157 T obj; 158 159 yamlNode.deserializeInto(obj); 160 return obj; 161 }