1 module jsonserialized.serialization;
2 
3 import std.conv;
4 import stdx.data.json;
5 import std.traits;
6 
7 @safe:
8 
9 /// Convert the specified array into a JSONValue.
10 pure JSONValue serializeToJSONValue(T)(in ref T array) if (isArray!T) {
11     alias ElementType = ForeachType!T;
12 
13     JSONValue[] values;
14 
15     // Iterate each item in the array and add them to the array of JSON values
16     foreach(item; array) {
17         static if (is(ElementType == struct)) {
18             // This item is a struct
19             values ~= item.serializeToJSONValue();
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                 values ~= item.serializeToJSONValue();
25             }
26         }
27         else static if (isSomeString!ElementType) {
28             values ~= JSONValue(item.to!string);
29         }
30         else static if (isArray!ElementType) {
31             // An array of arrays. Recursion time!
32             values ~= item.serializeToJSONValue();
33         }
34         else {
35             values ~= JSONValue(item);
36         }
37     }
38 
39     return JSONValue(values);
40 }
41 
42 /// Convert the specified associative array into a JSONValue.
43 pure JSONValue serializeToJSONValue(T)(in ref T associativeArray) if (isAssociativeArray!T) {
44     alias VType = ValueType!T;
45 
46     JSONValue[string] items;
47 
48     // Iterate each item in the associative array
49     foreach(key, value; associativeArray) {
50         // JSON keys have to be strings, so convert every key to a string
51         auto stringKey = key.to!string;
52 
53         static if (is(VType == struct)) {
54             // The value type is struct
55             items[stringKey] = value.serializeToJSONValue();
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[stringKey] = value.serializeToJSONValue();
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[stringKey] = value.serializeToJSONValue();
67         }
68         else static if (isSomeString!VType) {
69             items[stringKey] = JSONValue(value.to!string);
70         }
71         else {
72             items[stringKey] = JSONValue(value);
73         }
74     }
75 
76     return JSONValue(items);
77 }
78 
79 /// Convert the specified struct or class into a JSONValue.
80 pure JSONValue serializeToJSONValue(T)(in ref T obj) if (is(T == struct) || is(T == class)) {
81     enum fieldNames = FieldNameTuple!T;
82 
83     JSONValue[string] jsonValues;
84 
85     foreach(fieldName; fieldNames) {
86         auto field = __traits(getMember, obj, fieldName);
87         alias FieldType = typeof(field);
88 
89         static if (is(FieldType == struct)) {
90             // This field is a struct - recurse into it
91             jsonValues[fieldName] = field.serializeToJSONValue();
92         }
93         else static if (is(FieldType == class)) {
94             // This field is a class - recurse into it unless it is null
95             if (field !is null) {
96                 jsonValues[fieldName] = field.serializeToJSONValue();
97             }
98         }
99         else static if (isSomeString!FieldType) {
100             // Because JSONValue only seems to work with string strings (and not char[], etc), convert all string types to string
101             jsonValues[fieldName] = JSONValue(field.to!string);
102         }
103         else static if (isArray!FieldType) {
104             // Field is an array
105             jsonValues[fieldName] = field.serializeToJSONValue();
106         }
107         else static if (isAssociativeArray!FieldType) {
108             // Field is an associative array
109             jsonValues[fieldName] = field.serializeToJSONValue();
110         }
111         else {
112             jsonValues[fieldName] = JSONValue(field);
113         }
114     }
115 
116     return JSONValue(jsonValues);
117 }