1 module libpb.deserialization;
2 
3 import std.json;
4 import std.traits : FieldTypeTuple, FieldNameTuple;
5 
6 public RecordType fromJSON(RecordType)(JSONValue jsonIn)
7 {
8 	RecordType record;
9 
10 	// Alias as to only expand later when used in compile-time
11 	alias structTypes = FieldTypeTuple!(RecordType);
12 	alias structNames = FieldNameTuple!(RecordType);
13 	alias structValues = record.tupleof;
14 
15 	static foreach(cnt; 0..structTypes.length)
16 	{
17 		debug(dbg)
18 		{
19 			pragma(msg, structTypes[cnt]);
20 			pragma(msg, structNames[cnt]);
21 			// pragma(msg, structValues[cnt]);
22 		}
23 
24 		static if(__traits(isSame, mixin(structTypes[cnt]), byte))
25 		{
26 			mixin("record."~structNames[cnt]) = cast(byte)jsonIn[structNames[cnt]].integer();
27 		}
28 		else static if(__traits(isSame, mixin(structTypes[cnt]), ubyte))
29 		{
30 			mixin("record."~structNames[cnt]) = cast(ubyte)jsonIn[structNames[cnt]].uinteger();
31 		}
32 		else static if(__traits(isSame, mixin(structTypes[cnt]), short))
33 		{
34 			mixin("record."~structNames[cnt]) = cast(short)jsonIn[structNames[cnt]].integer();
35 		}
36 		else static if(__traits(isSame, mixin(structTypes[cnt]), ushort))
37 		{
38 			mixin("record."~structNames[cnt]) = cast(ushort)jsonIn[structNames[cnt]].uinteger();
39 		}
40 		else static if(__traits(isSame, mixin(structTypes[cnt]), int))
41 		{
42 			mixin("record."~structNames[cnt]) = cast(int)jsonIn[structNames[cnt]].integer();
43 		}
44 		else static if(__traits(isSame, mixin(structTypes[cnt]), uint))
45 		{
46 			mixin("record."~structNames[cnt]) = cast(uint)jsonIn[structNames[cnt]].uinteger();
47 		}
48 		else static if(__traits(isSame, mixin(structTypes[cnt]), ulong))
49 		{
50 			mixin("record."~structNames[cnt]) = cast(ulong)jsonIn[structNames[cnt]].uinteger();
51 		}
52 		else static if(__traits(isSame, mixin(structTypes[cnt]), long))
53 		{
54 			mixin("record."~structNames[cnt]) = cast(long)jsonIn[structNames[cnt]].integer();
55 		}
56 		else static if(__traits(isSame, mixin(structTypes[cnt]), string))
57 		{
58 			mixin("record."~structNames[cnt]) = jsonIn[structNames[cnt]].str();
59 
60 			debug(dbg)
61 			{
62 				pragma(msg,"record."~structNames[cnt]);
63 			}
64 		}
65 		else static if(__traits(isSame, mixin(structTypes[cnt]), JSONValue))
66 		{
67 			mixin("record."~structNames[cnt]) = jsonIn[structNames[cnt]];
68 
69 			debug(dbg)
70 			{
71 				pragma(msg,"record."~structNames[cnt]);
72 			}
73 		}
74 		else static if(__traits(isSame, mixin(structTypes[cnt]), bool))
75 		{
76 			mixin("record."~structNames[cnt]) = jsonIn[structNames[cnt]].boolean();
77 
78 			debug(dbg)
79 			{
80 				pragma(msg,"record."~structNames[cnt]);
81 			}
82 		}
83 		//FIXME: Not sure how to get array support going, very new to meta programming
84 		else static if(__traits(isSame, mixin(structTypes[cnt]), mixin(structTypes[cnt])[]))
85 		{
86 			mixin("record."~structNames[cnt]) = jsonIn[structNames[cnt]].boolean();
87 
88 			debug(dbg)
89 			{
90 				pragma(msg,"record."~structNames[cnt]);
91 			}
92 		}
93 		else
94 		{
95 			// throw new
96 			//TODO: Throw error
97 			debug(dbg)
98 			{
99 				pragma(msg, "Unknown type for de-serialization");
100 			}
101 		}
102 	}
103 
104 	return record;
105 }
106 
107 unittest
108 {
109 	import std.string : cmp;
110 	import std.stdio : writeln;
111 	
112 	struct Person
113 	{
114 		public string firstname, lastname;
115 		public int age;
116 		public bool isMale;
117 		public JSONValue obj;
118 		public int[] list;
119 	}
120 	
121 	JSONValue json = parseJSON(`{
122 "firstname" : "Tristan",
123 "lastname": "Kildaire",
124 "age": 23,
125 "obj" : {"bruh":1},
126 "isMale": true,
127 "list": [1,2,3]
128 }
129 `);
130 
131 	Person person = fromJSON!(Person)(json);
132 
133 	debug(dbg)
134 	{
135 		writeln(person);	
136 	}
137 
138 	assert(cmp(person.firstname, "Tristan") == 0);
139 	assert(cmp(person.lastname, "Kildaire") == 0);
140 	assert(person.age == 23);
141 	assert(person.isMale == true);
142 	assert(person.obj["bruh"].integer() == 1);
143 	//TODO: list test case
144 }