1 module hunt.serialization.specify;
2 
3 import std.traits;
4 import std.range;
5 import hunt.serialization.BinarySerializer;
6 import hunt.serialization.BinaryDeserializer;
7 
8 template PtrType(T) {
9   static if(is(T == bool) || is(T == char)) {
10     alias PtrType = ubyte*;
11   } else static if(is(T == float)) {
12     alias PtrType = uint*;
13   } else static if(is(T == double)) {
14       alias PtrType = ulong*;
15     } else {
16       alias PtrType = Unsigned!T*;
17     }
18 }
19 
20 enum NULL = [110, 117, 108, 108];
21 
22 void specify(C, T)(auto ref C obj, ref T val) if(is(T == wchar)) {
23   specify(obj , *cast(ushort*)&val);
24 }
25 
26 void specify(C, T)(auto ref C obj, ref T val) if(is(T == dchar)) {
27   specify(obj , *cast(uint*)&val);
28 }
29 
30 void specify(C, T)(auto ref C obj, ref T val) if(is(T == ushort)) {
31   ubyte valh = (val >> 8);
32   ubyte vall = val & 0xff;
33   obj.putUbyte(valh);
34   obj.putUbyte(vall);
35   val = (valh << 8) + vall;
36 }
37 
38 void specify(C, T)(auto ref C obj, ref T val) if(is(T == uint)) {
39   ubyte val0 = (val >> 24);
40   ubyte val1 = cast(ubyte)(val >> 16);
41   ubyte val2 = cast(ubyte)(val >> 8);
42   ubyte val3 = val & 0xff;
43   obj.putUbyte(val0);
44   obj.putUbyte(val1);
45   obj.putUbyte(val2);
46   obj.putUbyte(val3);
47   val = (val0 << 24) + (val1 << 16) + (val2 << 8) + val3;
48 }
49 
50 void specify(C, T)(auto ref C obj, ref T val) if(is(T == ulong)) {
51   T newVal;
52   for(int i = 0; i < T.sizeof; ++i) {
53     immutable shiftBy = 64 - (i + 1) * T.sizeof;
54     ubyte byteVal = (val >> shiftBy) & 0xff;
55     obj.putUbyte(byteVal);
56     newVal |= (cast(T)byteVal << shiftBy);
57   }
58   val = newVal;
59 }
60 
61 //静态数组
62 void specify(C, T)(auto ref C obj, ref T val) if(isStaticArray!T) {
63   static if(is(Unqual!(ElementType!T): ubyte) && T.sizeof == 1)
64   {
65     obj.putRaw(cast(ubyte[])val);
66   }
67   else
68   {
69     foreach(ref v; val)
70     {
71       specify(obj ,v);
72     }
73   }
74 }
75 
76 //string
77 void specify(C, T)(auto ref C obj, ref T val) if(is(T == string))
78 {
79   ushort len = cast(ushort)val.length;
80   specify(obj , len);
81 
82   static if (is (C == BinarySerializer))
83   {
84     obj.putRaw(cast(ubyte[])val);
85   }
86   else
87   {
88     val = cast(string) obj.putRaw(len).idup;
89   }
90 }
91 
92 //基础类型数组
93 void specify(C, T)(auto ref C obj, ref T val) if(isAssociativeArray!T)
94 {
95   ushort length = cast(ushort)val.length;
96   specify(obj , length);
97   const keys = val.keys;
98   for(ushort i = 0; i < length; ++i) {
99     KeyType!T k = keys.length ? keys[i] : KeyType!T.init;
100     auto v = keys.length ? val[k] : ValueType!T.init;
101 
102     specify(obj ,k);
103     specify(obj ,v);
104     val[k] = v;
105   }
106 }
107 
108 void specify(C, T)(auto ref C obj, ref T val) if(isPointer!T) {
109   alias ValueType = PointerTarget!T;
110   specify(obj , *val);
111 }
112 
113 
114 
115 //ubyte
116 void specify(C, T)(auto ref C obj, ref T val) if(is(T == ubyte))
117 {
118   obj.putUbyte(val);
119 }
120 
121 //有符号类型
122 void specify(C, T)(auto ref C obj, ref T val) if(!is(T == enum) && (isSigned!T || isBoolean!T || is(T == char) || isFloatingPoint!T))
123 {
124   specifyPtr(obj , val);
125 }
126 
127 //ENUM
128 void specify(C, T)(auto ref C obj, ref T val) if(is(T == enum))
129 {
130   specify(obj , cast(Unqual!(OriginalType!(T)))val );
131 }
132 
133 void specify(C, T)(auto ref C obj, ref T val) if(is(C == BinarySerializer) && isInputRange!T && !isInfinite!T && !is(T == string) && !isStaticArray!T && !isAssociativeArray!T)
134 {
135   enum hasLength = is(typeof(() { auto l = val.length; }));
136   ushort length = cast(ushort)val.length;
137   specify(obj, length);
138 
139   static if(hasSlicing!(Unqual!T) && is(Unqual!(ElementType!T): ubyte) && T.sizeof == 1)
140   {
141     obj.putRaw(cast(ubyte[])val.array);
142   }
143   else
144   {
145     foreach(ref v; val)
146     {
147       specify(obj , v);
148     }
149   }
150 }
151 
152 
153 void specify(C, T)(auto ref C obj, ref T val) if(isAggregateType!T && !isInputRange!T && !isOutputRange!(T, ubyte))
154 {
155   loopMembers(obj , val);
156 }
157 
158 //自定义数组
159 void specify(C, T)(auto ref C obj, ref T val) if(isDecerealiser!C && !isOutputRange!(T, ubyte) && isDynamicArray!T && !is(T == string)) {
160   ushort length;
161 
162   specify(obj,length);
163   decerealiseArrayImpl(obj, val, length);
164 }
165 
166 void decerealiseArrayImpl(C, T, U)(auto ref C obj, ref T val, U length) if(is(T == E[], E) && isDecerealiser!C)
167 {
168 
169   ulong neededBytes(T)(ulong length) {
170     alias E = ElementType!T;
171     static if(isScalarType!E)
172       return length * E.sizeof;
173     else static if(isInputRange!E)
174       return neededBytes!E(length);
175     else
176       return 0;
177   }
178 
179   immutable needed = neededBytes!T(length);
180 
181   static if(is(Unqual!(ElementType!T): ubyte) && T.sizeof == 1) {
182     val = obj.putRaw(length).dup;
183   } else {
184     if(val.length != length) val.length = cast(uint)length;
185     foreach(ref e; val) obj.specify(e);
186   }
187 }
188 
189 
190 void specifyPtr(C, T)(auto ref C obj, ref T val)
191 {
192   auto ptr = cast(PtrType!T)(&val);
193   specify(obj , *ptr);
194 }
195 
196 void loopMembers(C, T)(auto ref C obj, ref T val) if(is(T == struct))
197 {
198   loopMembersImpl!T(obj , val);
199 }
200 
201 void loopMembers(C, T)(auto ref C obj, ref T val) if(is(T == class))
202 {
203 
204   static if(is (C == BinarySerializer))
205   {
206     if (val is null)
207     {
208       obj.putRaw(NULL);
209       return;
210     }
211     //assert(val !is null, "null value cannot be serialised");
212   }
213 
214   static if (is (C == BinaryDeserializer))
215   {
216     if (obj.isNullObj)
217     {
218       val = null;
219       return;
220     }
221   }
222 
223   static if(is(typeof(() { val = new T; }))) {
224     if(val is null) val = new T;
225   } else {
226   }
227 
228   obj.putClass(val);
229 }
230 
231 
232 
233 void loopMembersImpl(T, C, VT) (auto ref C obj, ref VT val)
234 {
235   foreach(member; __traits(derivedMembers, T)) {
236     enum isMemberVariable = is(typeof(() {
237       __traits(getMember, val, member) = __traits(getMember, val, member).init;
238     }));
239     static if(isMemberVariable) {
240       specifyAggregateMember!member(obj , val);
241     }
242   }
243 }
244 
245 void specifyAggregateMember(string member, C, T)(auto ref C obj, ref T val)
246 {
247   import std.meta: staticIndexOf;
248   enum NoCereal;
249   enum noCerealIndex = staticIndexOf!(NoCereal, __traits(getAttributes,__traits(getMember, val, member)));
250   static if(noCerealIndex == -1) {
251     specifyMember!member(obj, val);
252   }
253 }
254 
255 void specifyMember(string member, C, T)(auto ref C obj, ref T val)
256 {
257   specify( obj , __traits(getMember, val, member));
258 }
259 
260 void specifyBaseClass(C, T)(auto ref C obj, ref T val) if(is(T == class))
261 {
262   foreach(base; BaseTypeTuple!T)
263   {
264     loopMembersImpl!base(obj ,val);
265   }
266 }
267 
268 
269 void specifyClass(C, T)(auto ref C obj, ref T val) if(is(T == class))
270 {
271   specifyBaseClass(obj, val);
272   loopMembersImpl!T(obj, val);
273 }
274 
275 void checkDecerealiser(T)() {
276   //static assert(T.type == CerealType.ReadBytes);
277   auto dec = T();
278   ulong bl = dec.bytesLeft;
279 }
280 
281 enum isDecerealiser(T) =  (is (T == BinaryDeserializer) && is(typeof(checkDecerealiser!T))) ;