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