1 module yamlserialized.serialization; 2 3 import std.conv; 4 import std.traits; 5 6 import yamlserialized.types; 7 8 import dyaml; 9 10 @safe: 11 12 /// Convert an array of type T to a D-YAML Node 13 Node toYAMLNode(T)(in ref T array) if (isArray!T) { 14 alias ElementType = ForeachType!T; 15 16 Node[] nodes; 17 18 // Iterate each item in the array and add them to the array of nodes 19 foreach(item; array) { 20 static if (is(ElementType == struct)) { 21 // This item is a struct 22 nodes ~= item.toYAMLNode(); 23 } 24 else static if (is(ElementType == class)) { 25 // This item is a class - serialize it unless it is null 26 if (item !is null) { 27 nodes ~= item.toYAMLNode(); 28 } 29 } 30 else static if (isSomeString!ElementType) { 31 nodes ~= Node(item.to!string); 32 } 33 else static if (isArray!ElementType) { 34 // An array of arrays. Recursion time! 35 nodes ~= item.toYAMLNode(); 36 } 37 else { 38 nodes ~= Node(item); 39 } 40 } 41 42 return Node(nodes); 43 } 44 45 /// Convert an associative array of type T to a D-YAML Node 46 Node toYAMLNode(T)(in ref T associativeArray) if (isAssociativeArray!T) { 47 alias KType = KeyType!T; 48 alias VType = ValueType!T; 49 50 Node[KType] items; 51 52 // Iterate each item in the associative array 53 foreach(key, value; associativeArray) { 54 // Convert key to the correct type 55 auto typedKey = key.to!KType; 56 57 static if (is(VType == struct)) { 58 // The value type is struct 59 items[typedKey] = value.toYAMLNode(); 60 } 61 else static if (is(VType == class)) { 62 // The value is a class - serialize it unless it is null 63 if (value !is null) { 64 items[typedKey] = value.toYAMLNode(); 65 } 66 } 67 else static if (isAssociativeArray!VType) { 68 /* The associative array's value type is another associative array type. 69 It's recursion time. */ 70 items[typedKey] = value.toYAMLNode(); 71 } 72 else static if (isSomeString!VType) { 73 items[typedKey] = Node(value.to!string); 74 } 75 else { 76 items[typedKey] = Node(value); 77 } 78 } 79 80 return Node(items); 81 } 82 83 /// Convert a struct or class of type T to a D-YAML Node 84 Node toYAMLNode(T)(in ref T obj) if (is(T == struct) || is(T == class)) { 85 enum fieldNames = FieldNameTuple!T; 86 87 Node[string] nodes; 88 89 foreach(fieldName; fieldNames) { 90 auto field = __traits(getMember, obj, fieldName); 91 92 auto yamlFieldName = fieldName; 93 94 static if (hasUDA!(__traits(getMember, obj, fieldName), YamlField)) { 95 yamlFieldName = getUDAs!(__traits(getMember, obj, fieldName), YamlField)[0].name; 96 } 97 98 alias FieldType = typeof(field); 99 100 static if (is(FieldType == struct)) { 101 // This field is a struct - recurse into it 102 nodes[yamlFieldName] = field.toYAMLNode(); 103 } 104 else static if (is(FieldType == class)) { 105 // This field is a class - recurse into it unless it is null 106 if (field !is null) { 107 nodes[yamlFieldName] = field.toYAMLNode(); 108 } 109 } 110 else static if (isSomeChar!FieldType || isSomeString!FieldType) { 111 // Because Node only seems to work with string strings (and not char[], etc), convert all string types to string 112 nodes[yamlFieldName] = Node(field.to!string); 113 } 114 else static if (isArray!FieldType) { 115 // Field is an array 116 nodes[yamlFieldName] = field.toYAMLNode(); 117 } 118 else static if (isAssociativeArray!FieldType) { 119 // Field is an associative array 120 nodes[yamlFieldName] = field.toYAMLNode(); 121 } 122 else { 123 nodes[yamlFieldName] = Node(field.to!FieldType); 124 } 125 } 126 127 return Node(nodes); 128 }