1 /**
2  * Serialization utilities
3  */
4 module jstruct.serializer;
5 
6 import std.json;
7 import std.conv : to;
8 import std.traits : FieldTypeTuple, FieldNameTuple;
9 import std.traits : isArray;
10 
11 /** 
12  * Serializes the provided record into JSON
13  *
14  * Params:
15  *   record = the record to serialize into
16  * Returns: A `JSONValue` containing the serialized record
17  */
18 public JSONValue serializeRecord(RecordType)(RecordType record)
19 {		
20 	// Final JSON to submit
21 	JSONValue builtJSON;
22 
23 	// Alias as to only expand later when used in compile-time
24 	alias structTypes = FieldTypeTuple!(RecordType);
25 	alias structNames = FieldNameTuple!(RecordType);
26 	alias structValues = record.tupleof;
27 
28 	static foreach(cnt; 0..structTypes.length)
29 	{
30 		debug(dbg)
31 		{
32 			pragma(msg, structTypes[cnt]);
33 			pragma(msg, structNames[cnt]);
34 			// pragma(msg, structValues[cnt]);
35 		}
36 
37 		static if(__traits(isSame, structTypes[cnt], int))
38 		{
39 			builtJSON[structNames[cnt]] = structValues[cnt];
40 		}
41 		else static if(__traits(isSame, structTypes[cnt], uint))
42 		{
43 			builtJSON[structNames[cnt]] = structValues[cnt];
44 		}
45 		else static if(__traits(isSame, structTypes[cnt], ulong))
46 		{
47 			builtJSON[structNames[cnt]] = structValues[cnt];
48 		}
49 		else static if(__traits(isSame, structTypes[cnt], long))
50 		{
51 			builtJSON[structNames[cnt]] = structValues[cnt];
52 		}
53 		else static if(__traits(isSame, structTypes[cnt], string))
54 		{
55 			builtJSON[structNames[cnt]] = structValues[cnt];
56 		}
57 		else static if(__traits(isSame, structTypes[cnt], JSONValue))
58 		{
59 			builtJSON[structNames[cnt]] = structValues[cnt];
60 		}
61 		else static if(__traits(isSame, structTypes[cnt], bool))
62 		{
63 			builtJSON[structNames[cnt]] = structValues[cnt];
64 		}
65 		else static if(isArray!(structTypes[cnt]))
66 		{
67 			builtJSON[structNames[cnt]] = structValues[cnt];
68 		}
69 		else
70 		{
71 			debug(dbg)
72 			{
73 				pragma(msg, "Yaa");	
74 			}
75 			builtJSON[structNames[cnt]] = to!(string)(structValues[cnt]);
76 		}
77 	}
78 
79 
80 	return builtJSON;
81 }
82 
83 // Test serialization of a struct to JSON
84 
85 
86 version(unittest)
87 {
88 	import std.algorithm.searching : canFind;
89 	import std.string : cmp;
90 	import std.stdio : writeln;
91 }
92 
93 /**
94  * Example serialization of our struct
95  * `Person` to JSON
96  */
97 unittest
98 {
99 	enum EnumType
100 	{
101 		DOG,
102 		CAT
103 	}
104 
105 	struct Person
106 	{
107 		public string firstname, lastname;
108 		public int age;
109 		public string[] list;
110 		public JSONValue extraJSON;
111 		public EnumType eType;
112 	}
113 
114 	Person p1;
115 	p1.firstname  = "Tristan";
116 	p1.lastname = "Kildaire";
117 	p1.age = 23;
118 	p1.list = ["1", "2", "3"];
119 	p1.extraJSON = parseJSON(`{"item":1, "items":[1,2,3]}`);
120 	p1.eType = EnumType.CAT;
121 
122 	JSONValue serialized = serializeRecord(p1);
123 
124 	string[] keys = serialized.object().keys();
125 	assert(canFind(keys, "firstname") && cmp(serialized["firstname"].str(), "Tristan") == 0);
126 	assert(canFind(keys, "lastname") && cmp(serialized["lastname"].str(), "Kildaire") == 0);
127 	assert(canFind(keys, "age") && serialized["age"].integer() == 23);
128 
129 	assert(canFind(keys, "list"));
130 	JSONValue[] elems = serialized["list"].array();
131 	for(ulong i = 0; i < elems.length; i++)
132 	{
133 		string curElem = elems[i].str();
134 		assert(curElem == p1.list[i]);
135 	}
136 
137 	debug(dbg)
138 	{
139 		writeln(serialized.toPrettyString());
140 	}
141 }