1 /*
2  * Geario - A cross-platform abstraction library with asynchronous I/O.
3  *
4  * Copyright (C) 2021-2022 Kerisy.com
5  *
6  * Website: https://www.kerisy.com
7  *
8  * Licensed under the Apache-2.0 License.
9  *
10  */
11 
12 
13 deprecated("It's buggy. Use geario.serialization.JsonSerializer instead.")
14 module geario.util.Serialize;
15 
16 import std.traits;
17 import std.string;
18 import core.stdc.string;
19 import std.stdio;
20 import std.bitmanip;
21 import std.math;
22 public import std.json;
23 
24 public:
25 enum IGNORE = 1024;
26 
27 class UnIgnoreArray{
28     
29     void setUnIgnore(T)()
30     {
31         _unIgnore[T.stringof] = true;
32     }
33 
34     bool ignore(T)()
35     {
36         return T.stringof !in _unIgnore;
37     }
38 
39 private:
40     bool[string] _unIgnore;
41 }
42 
43 
44 private:
45 
46 class RefClass
47 {
48     size_t[size_t] map;
49     void*[] arr;
50     uint level;
51     bool ignore;                     ///  all class or struct ignore or not. 
52     UnIgnoreArray unIgnore;            ///  part class unignore. 
53 }
54 
55 enum MAGIC_KEY = "o0o0o";
56 
57 enum bool isType(T1, T2) = is(T1 == T2) || is(T1 == ImmutableOf!T2)
58         || is(T1 == ConstOf!T2) || is(T1 == InoutOf!T2)
59         || is(T1 == SharedOf!T2) || is(T1 == SharedConstOf!T2) || is(T1 == SharedInoutOf!T2);
60 
61 enum bool isSignedType(T) = isType!(T, byte) || isType!(T, short) || isType!(T,
62             int) || isType!(T, long);
63 enum bool isUnsignedType(T) = isType!(T, ubyte) || isType!(T, ushort)
64         || isType!(T, uint) || isType!(T, ulong);
65 enum bool isBigSignedType(T) = isType!(T, int) || isType!(T, long);
66 enum bool isBigUnsignedType(T) = isType!(T, uint) || isType!(T, ulong);
67 
68 //unsigned
69 ulong[] byte_dots = [1 << 7, 1 << 14, 1 << 21, 1 << 28, cast(ulong) 1 << 35,
70     cast(ulong) 1 << 42, cast(ulong) 1 << 49, cast(ulong) 1 << 56, cast(ulong) 1 << 63,];
71 
72 //signed
73 ulong[] byte_dots_s = [1 << 6, 1 << 13, 1 << 20, 1 << 27, cast(ulong) 1 << 34,
74     cast(ulong) 1 << 41, cast(ulong) 1 << 48, cast(ulong) 1 << 55, cast(ulong) 1 << 62,];
75 
76 ubyte getbytenum(ulong v)
77 {
78     ubyte i = 0;
79     for (; i < byte_dots.length; i++)
80     {
81         if (v < byte_dots[i])
82         {
83             break;
84         }
85     }
86     return cast(ubyte)(i + 1);
87 }
88 
89 ubyte getbytenums(ulong v)
90 {
91     ubyte i = 0;
92     for (; i < byte_dots_s.length; i++)
93     {
94         if (v < byte_dots_s[i])
95         {
96             break;
97         }
98     }
99 
100     return cast(ubyte)(i + 1);
101 }
102 
103 //signed
104 byte[] toVariant(T)(T t) if (isSignedType!T)
105 {
106     bool symbol = false;
107     if (t < 0)
108         symbol = true;
109 
110     ulong val = cast(ulong) abs(t);
111 
112     ubyte num = getbytenums(val);
113 
114     ubyte[] var;
115     if(num == 1)
116     {
117         if (symbol)
118             val = val | 0x40;
119     }
120     else{
121         for (size_t i = num; i > 1; i--)
122         {
123             auto n = val / (byte_dots_s[i - 2] * 2);
124             if (symbol && i == num)
125                 n = n | 0x40;
126             var ~= cast(ubyte) n;
127             val = (val % (byte_dots_s[i - 2] * 2));
128         }
129     }
130 
131     var ~= cast(ubyte)(val | 0x80);
132     return cast(byte[]) var;
133 }
134 
135 T toT(T)(const byte[] b, out long index) if (isSignedType!T)
136 {
137     T val = 0;
138     ubyte i = 0;
139     bool symbol = false;
140 
141     if(b.length == 1)
142     {
143         val = (b[i] & 0x3F);
144         if (b[i] & 0x40)
145             symbol = true;
146     }
147     else
148     {
149         for (i = 0; i < b.length; i++)
150         {
151             if (i == 0)
152             {
153                 val = (b[i] & 0x3F);
154                 if (b[i] & 0x40)
155                     symbol = true;            
156             }
157             else
158             {
159                 val = cast(T)((val << 7) + (b[i] & 0x7F));
160             }
161         
162             if (b[i] & 0x80)
163                 break;
164         }
165     }
166 
167     index = i + 1;
168     if (symbol)
169         return cast(T)(val * -1);
170     else
171         return val;
172 }
173 
174 //unsigned
175 byte[] toVariant(T)(T t) if (isUnsignedType!T)
176 {
177     ubyte num = getbytenum(cast(ulong) t);
178     T val = t;
179     ubyte[] var;
180     for (size_t i = num; i > 1; i--)
181     {
182         auto n = val / (byte_dots[i - 2]);
183         var ~= cast(ubyte) n;
184         val = val % (byte_dots[i - 2]);
185     }
186     var ~= cast(ubyte)(val | 0x80);
187     return cast(byte[]) var;
188 }
189 
190 //unsigned
191 T toT(T)(const byte[] b, out long index) if (isUnsignedType!T)
192 {
193     T val = 0;
194     ubyte i = 0;
195     for (i = 0; i < b.length; i++)
196     {
197 
198         val = cast(T)((val << 7) + (b[i] & 0x7F));
199         if (b[i] & 0x80)
200             break;
201     }
202     index = i + 1;
203     return val;
204 }
205 
206 byte getbasictype(long size)
207 {
208     if (size == 1)
209         return 0;
210     else if (size == 2)
211         return 1;
212     else if (size == 4)
213         return 2;
214     else if (size == 8)
215         return 3;
216     else
217         assert(0);
218 }
219 
220 byte getbasicsize(byte type)
221 {
222     if (type == 0)
223         return 1;
224     else if (type == 1)
225         return 2;
226     else if (type == 2)
227         return 4;
228     else if (type == 3)
229         return 8;
230     else
231         assert(0);
232 }
233 
234 string serializeMembers(T)()
235 {
236     string str;
237     foreach (m; FieldNameTuple!T)
238     {
239         static if (__traits(getProtection, __traits(getMember, T, m)) == "public")
240         {
241             str ~= "data ~= Serialize(t." ~ m ~ " , stack , level + 1);";
242         }
243     }
244     return str;
245 }
246 
247 string unserializeMembers(T)()
248 {
249     string str;
250     // str ~= "long parse = 0; ";
251     foreach (m; FieldNameTuple!T)
252     {
253         static if (__traits(getProtection, __traits(getMember, T, m)) == "public")
254         {
255             str ~= " if ( index < parse_index)";
256             str ~= "{";
257             str ~= "t." ~ m ~ " = unserialize!(typeof(t." ~ m
258                 ~ "))(data[cast(uint)index .. data.length] , parse , stack); ";
259             str ~= "index += parse; }";
260         }
261 
262     }
263     return str;
264 }
265 
266 string getsizeMembers(T)()
267 {
268     string str;
269     foreach (m; FieldNameTuple!T)
270     {
271         static if (__traits(getProtection, __traits(getMember, T, m)) == "public")
272         {
273         str ~= "total += getsize(t." ~ m ~ " , stack , level + 1);";
274         }        
275     }
276     return str;
277 }
278 
279 ///////////////////////////////////////////////////////////
280 // basic
281 // type           size
282 //  0     -         1
283 //  1     -            2
284 //  2     -            4
285 //  3     -             8
286 //    data
287 ///////////////////////////////////////////////////////////
288 ///
289 byte[] Serialize(T)(T t, RefClass stack, uint level)
290         if (isScalarType!T && !isBigSignedType!T && !isBigUnsignedType!T && !is(T == enum))
291 {
292     byte[] data;
293     data.length = T.sizeof + 1;
294     data[0] = getbasictype(T.sizeof);
295     memcpy(data.ptr + 1, &t, T.sizeof);
296     return data;
297 }
298 
299 T Unserialize(T)(const byte[] data, out long parse_index, RefClass stack)
300         if (isScalarType!T && !isBigSignedType!T && !isBigUnsignedType!T && !is(T == enum))
301 {
302     assert(cast(byte) T.sizeof == getbasicsize(data[0]));
303 
304     T value;
305     memcpy(&value, data.ptr + 1, T.sizeof);
306 
307     parse_index = T.sizeof + 1;
308     return value;
309 }
310 
311 size_t getsize(T)(T t, RefClass stack, uint level)
312         if (isScalarType!T && !isBigSignedType!T && !isBigUnsignedType!T && !is(T == enum))
313 {
314     return T.sizeof + 1;
315 }
316 
317 ///////////////////////////////////////////////////////////
318 // variant
319 // type           size
320 //  5 (4)    -         
321 //  6 (8)     -
322 //    data
323 ///////////////////////////////////////////////////////////
324 byte[] Serialize(T)(T t, RefClass stack, uint level)
325         if (isBigSignedType!T || isBigUnsignedType!T)
326 {
327     byte[] data = toVariant!T(t);
328     long index;
329     byte[1] h;
330     h[0] = (T.sizeof == 4) ? 5 : 8;
331     return h ~ data;
332 }
333 
334 T Unserialize(T)(const byte[] data, out long parse_index, RefClass stack)
335         if (isBigSignedType!T || isBigUnsignedType!T)
336 {
337     assert((T.sizeof == 4 ? 5 : 8) == data[0]);
338     long index;
339     T t = toT!T(data[1 .. $], index);
340     parse_index = index + 1;
341     return t;
342 }
343 
344 size_t getsize(T)(T t, RefClass stack, uint level) if (isBigSignedType!T)
345 {
346     return getbytenums(abs(t)) + 1;
347 }
348 
349 size_t getsize(T)(T t, RefClass stack, uint level) if (isBigUnsignedType!T)
350 {
351     return getbytenum(abs(t)) + 1;
352 }
353 
354 // TString
355 // 1 type 7
356 // [uint] variant 
357 //  data
358 
359 byte[] Serialize(T)(T str, RefClass stack, uint level) if (is(T == string))
360 {
361     byte[] data;
362     uint len = cast(uint) str.length;
363     byte[] dlen = toVariant(len);
364     data.length = 1 + dlen.length + len;
365 
366     data[0] = 7;
367     memcpy(data.ptr + 1, dlen.ptr, dlen.length);
368     memcpy(data.ptr + 1 + dlen.length, str.ptr, len);
369     return data;
370 }
371 
372 string Unserialize(T)(const byte[] data, out long parse_index, RefClass stack)
373         if (is(T == string))
374 {
375     assert(data[0] == 7);
376     long index;
377     uint len = toT!uint(data[1 .. $], index);
378     parse_index += 1 + index + len;
379     return cast(T)(data[cast(size_t)(1 + index) .. cast(size_t) parse_index].dup);
380 }
381 
382 size_t getsize(T)(T str, RefClass stack, uint level) if (is(T == string))
383 {
384     uint len = cast(uint) str.length;
385     return cast(size_t)(1 + toVariant(len).length + str.length);
386 }
387 
388 // TUnion            don't support TUnion
389 // 1 type 6
390 // 1 len 
391 //      data
392 
393 /*
394 byte[] Serialize(T)(T t) if(is(T == union))
395 {
396     byte[] data;
397     data.length = T.sizeof + 2;
398     data[0] = 5;
399     data[1] = T.sizeof;
400     memcpy(data.ptr + 2 , &t , T.sizeof);
401     return data;
402 }
403 T Unserialize(T)(const byte[] data ) if(is(T == union))
404 {
405     long parser_index;
406     return unserialize!T(data , parser_index);
407 }
408 T Unserialize(T)(const byte[] data , out long parse_index) if(is(T == union))
409 {
410     assert(data[0] == 5);
411     
412     T value;
413     byte len;
414     memcpy(&len , data.ptr + 1 , 1);
415     parse_index = 2 + len;
416     memcpy(&value , data.ptr + 2 , len);
417     return value;
418 }
419 size_t getsize(T)(T t) if(is(T == union))
420 {
421     return 2 + T.sizeof;
422 }
423 */
424 
425 // TSArray
426 // 1 type 8
427 // size[uint] variant
428 // len[uint] variant
429 // data
430 
431 byte[] Serialize(T)(T t, RefClass stack, uint level) if (isStaticArray!T)
432 {
433     byte[1] header;
434     header[0] = 8;
435     uint uSize = cast(uint) t.length;
436     byte[] dh = cast(byte[]) header;
437     dh ~= toVariant(uSize);
438 
439     byte[] data;
440     for (size_t i = 0; i < uSize; i++)
441     {
442         data ~= Serialize(t[i], stack, level + 1);
443     }
444     uint len = cast(uint) data.length;
445     dh ~= toVariant(len);
446     return dh ~ data;
447 }
448 
449 T Unserialize(T)(const byte[] data, out long parse_index, RefClass stack)
450         if (isStaticArray!T)
451 {
452     assert(data[0] == 8);
453     T value;
454     uint uSize;
455     uint len;
456     long index1;
457     long index2;
458     uSize = toT!uint(data[1 .. $], index1);
459 
460     len = toT!uint(data[cast(size_t)(index1 + 1) .. $], index2);
461     parse_index += 1 + index1 + index2;
462 
463     long index = parse_index;
464     long parse = 0;
465     for (size_t i = 0; i < uSize; i++)
466     {
467         parse = 0;
468         value[i] = unserialize!(typeof(value[0]))(data[cast(size_t) index .. data.length],
469                 parse, stack);
470         index += parse;
471     }
472 
473     parse_index += len;
474 
475     return value;
476 }
477 
478 size_t getsize(T)(T t, RefClass stack, uint level) if (isStaticArray!T)
479 {
480     long total = 1;
481     total += getbytenum(t.length);
482     uint uSize = cast(uint) t.length;
483     for (size_t i = 0; i < uSize; i++)
484     {
485         total += getsize(t[i], stack, level + 1);
486     }
487     total += getbytenum(total);
488     return total;
489 }
490 
491 //  TDArray
492 // 1  type 9
493 // size[uint]    variant
494 // length[uint]    variant
495 // data
496 
497 byte[] Serialize(T)(T t, RefClass stack, uint level)
498         if (isDynamicArray!T && !is(T == string) && !is(T == enum))
499 {
500     byte[1] header;
501     header[0] = 9;
502 
503     uint uSize = cast(uint) t.length;
504     byte[] dh = cast(byte[]) header;
505     dh ~= toVariant(uSize);
506 
507     byte[] data;
508     for (size_t i = 0; i < uSize; i++)
509     {
510         data ~= Serialize(t[i], stack, level + 1);
511     }
512     uint len = cast(uint) data.length;
513     dh ~= toVariant(len);
514 
515     return dh ~ data;
516 }
517 
518 T Unserialize(T)(const byte[] data, out long parse_index, RefClass stack)
519         if (isDynamicArray!T && !is(T == string) && !is(T == enum))
520 {
521     assert(data[0] == 9);
522 
523     T value;
524     uint uSize;
525     uint len;
526     long index1;
527     long index2;
528     uSize = toT!uint(data[1 .. $], index1);
529     len = toT!uint(data[cast(size_t)(1 + index1) .. $], index2);
530 
531     parse_index += 1 + index1 + index2;
532     value.length = uSize;
533     ulong index = parse_index;
534     long parse = 0;
535     for (size_t i = 0; i < uSize; i++)
536     {
537         value[i] = unserialize!(typeof(value[0]))(data[cast(size_t) index .. data.length],
538                 parse, stack);
539         index += parse;
540     }
541     parse_index += len;
542 
543     return value;
544 }
545 
546 size_t getsize(T)(T t, RefClass stack, uint level)
547         if (isDynamicArray!T && !is(T == string) && !is(T == enum) )
548 {
549     long total = 1;
550     total += getbytenum(t.length);
551     uint uSize = cast(uint) t.length;
552     for (size_t i = 0; i < uSize; i++)
553     {
554         total += getsize(t[i], stack, level + 1);
555     }
556     total += getbytenum(total);
557     return total;
558 }
559 
560 // TStruct
561 // 1 type 10
562 // [uint] variant
563 // data
564 
565 byte[] Serialize(T)(T t, RefClass stack, uint level) if (is(T == struct))
566 {
567     byte[1] header;
568     header[0] = 10;
569     byte[] data;
570 
571     mixin(serializeMembers!T());
572     byte[] dh = cast(byte[]) header;
573     uint len = cast(uint) data.length;
574     dh ~= toVariant(len);
575     return dh ~ data;
576 }
577 
578 T Unserialize(T)(const byte[] data, out long parse_index, RefClass stack)
579         if (is(T == struct))
580 {
581     assert(data[0] == 10);
582 
583     T t;
584     long index1;
585     uint len = toT!uint(data[1 .. $], index1);
586 
587     parse_index = 1 + index1 + len;
588     long index = 1 + index1;
589     long parse = 0; 
590     mixin(unserializeMembers!T());
591 
592     return t;
593 }
594 
595 size_t getsize(T)(T t, RefClass stack, uint level) if (is(T == struct))
596 {
597     long total = 1;
598 
599     mixin(getsizeMembers!T());
600 
601     total += getbytenum(total);
602     return cast(uint) total;
603 }
604 
605 // TClass 
606 // 1 type 11
607 // [uint] len variant
608 //    data
609 
610 // TClass ref
611 // 1 type 12
612 // id variant
613 
614 byte[] Serialize(T, bool isRecursive=true)(T t, RefClass stack, uint level) if (is(T == class))
615 {
616     byte[1] header;
617     size_t* id = null;
618 
619     if (t !is null)
620     {
621         id = t.toHash() in stack.map;
622     }
623 
624     if (id == null)
625     {
626         header[0] = 11;
627         byte[] data;
628         byte[] dh = cast(byte[]) header;
629         if (t !is null)
630         {
631             stack.map[t.toHash()] = stack.map.length;
632             static if(isRecursive) {
633                 static foreach(S; BaseClassesTuple!(T)) {
634                     mixin(serializeMembers!S());
635                 }
636             }
637             mixin(serializeMembers!T());
638         }
639         uint len = cast(uint) data.length;
640         dh ~= toVariant(len);
641 
642         return dh ~ data;
643     }
644     else
645     {
646         header[0] = 12;
647         byte[] dh = cast(byte[]) header;
648         dh ~= toVariant(*id);
649         return dh;
650     }
651 
652 }
653 
654 T Unserialize(T)(const byte[] data, out long parse_index, RefClass stack)
655         if (is(T == class) && !isAbstractClass!T)
656 {
657     if(data.length < 2)
658         return T.init;
659         
660     assert(data[0] == 11 || data[0] == 12);
661 
662     if (data[0] == 11)
663     {
664         long index1;
665         uint len = toT!uint(data[1 .. $], index1);
666         if (len == 0)
667             return null;
668         T t = new T;
669         parse_index = index1 + 1 + len;
670         long index = index1 + 1;
671         stack.arr ~= cast(void*) t;
672 
673         long parse = 0; 
674 
675         static foreach(S; BaseClassesTuple!(T)) {
676             mixin(unserializeMembers!S());
677         }
678         mixin(unserializeMembers!T());
679 
680         return t;
681     }
682     else
683     {
684         long index1;
685         size_t id = toT!size_t(data[1 .. $], index1);
686         parse_index += index1 + 1;
687         return cast(T) stack.arr[id];
688     }
689 
690 }
691 
692 size_t getsize(T)(T t, RefClass stack, uint level) if (is(T == class))
693 {
694     long total = 1;
695 
696     size_t* id = null;
697 
698     if (t !is null)
699     {
700         id = t.toHash() in stack.map;
701     }
702 
703     if (id == null)
704     {
705         if (t !is null)
706         {
707             stack.map[t.toHash()] = stack.map.length;
708             mixin(getsizeMembers!T());
709         }
710 
711         total += getbytenum(total - 1);
712         return total;
713     }
714     else
715     {
716         return getbytenum(*id) + 1;
717     }
718 
719 }
720 
721 // AssociativeArray
722 // 1 type 13
723 // [uint] len variant
724 // (k,v)
725 
726 byte[] Serialize(T)(T t, RefClass stack, uint level) if (isAssociativeArray!T)
727 {
728     byte[1] header;
729     header[0] = 13;
730     byte[] dh;
731     dh ~= cast(byte[]) header;
732     byte[] data;
733     foreach (k, v; t)
734     {
735         data ~= Serialize(k, stack, level + 1);
736         data ~= Serialize(v, stack, level + 1);
737     }
738     uint len = cast(uint) data.length;
739     dh ~= toVariant(len);
740     return dh ~ data;
741 }
742 
743 T Unserialize(T)(const byte[] data, out long parse_index, RefClass stack)
744         if (isAssociativeArray!T)
745 {
746     assert(data[0] == 13);
747 
748     T t;
749     long index1;
750     uint len = toT!uint(data[1 .. $], index1);
751 
752     parse_index = index1 + 1 + len;
753     long index = index1 + 1;
754     while (index < parse_index)
755     {
756         long out_len;
757         auto k = unserialize!(KeyType!T)(data[index .. $], out_len, stack);
758         index += out_len;
759         out_len = 0;
760         auto v = unserialize!(ValueType!T)(data[index .. $], out_len, stack);
761         index += out_len;
762         t[k] = v;
763     }
764     return t;
765 }
766 
767 size_t getsize(T)(T t, RefClass stack, uint level) if (isAssociativeArray!T)
768 {
769     long total = 1;
770     foreach (k, v; t)
771     {
772         total += Serialize(k).length;
773         total += Serialize(v).length;
774     }
775     total += getbytenum(total - 1);
776     return total;
777 }
778 
779 // named enum
780 // 1 type 14
781 // 2 [uint] len 
782 // 3 other
783 byte[] Serialize(T)(T t, RefClass stack, uint level) if (is(T == enum))
784 {
785     byte[1] header;
786     header[0] = 14;
787     byte[] dh;
788     dh ~= cast(byte[]) header;
789     OriginalType!T v = cast(OriginalType!T)t;
790     byte[] data =  Serialize(v);
791     uint len = cast(uint)data.length;
792     dh ~= toVariant(len);
793     return dh ~ data;
794 }
795 
796 T Unserialize(T)(const byte[] data, out long parse_index, RefClass stack)
797         if (is(T == enum))
798 {
799     assert(data[0] == 14);
800 
801     T t;
802     long index1;
803     uint len = toT!uint(data[1 .. $], index1);
804 
805     parse_index = index1 + 1 + len;
806     long index = index1 + 1;
807     while (index < parse_index)
808     {
809         long out_len = 0;
810         t = cast(T)unserialize!(OriginalType!T)(data[index .. $], out_len, stack);
811         index += out_len;
812     }
813     return t;
814 }
815 
816 size_t getsize(T)(T t, RefClass stack, uint level) if (is(T == enum))
817 {
818     long total = 1;
819     
820     total += Serialize(cast(OriginalType!T)t).length;
821     
822     total += getbytenum(total - 1);
823     return total;
824 }
825 
826 
827 
828 public:
829 
830 T Unserialize(T)(const(ubyte)[] data ) {
831     return unserialize!(T)(cast(const byte[])data);
832 }
833 
834 T Unserialize(T)(const byte[] data )
835 {
836     long parse_index;
837     return unserialize!T(data, parse_index);
838 }
839 
840 T Unserialize(T)(const(ubyte)[] data, out long parse_index ) {
841     return unserialize!(T)(cast(const byte[])data, parse_index);
842 }
843 
844 T Unserialize(T)(const byte[] data, out long parse_index )
845 {
846     RefClass stack = new RefClass();
847     return unserialize!T(data, parse_index, stack);
848 }
849 
850 byte[] Serialize(T)(T t ) if (!is(T == class))
851 {
852     RefClass stack = new RefClass();
853     return serialize!T(t, stack, 0);
854 }
855 
856 byte[] Serialize(T, bool isRecursive=true)(T t ) if (is(T == class))
857 {
858     RefClass stack = new RefClass();
859     return serialize!(T, isRecursive)(t, stack, 0);
860 }
861 
862 size_t getsize(T)(T t )
863 {
864     RefClass stack = new RefClass();
865     return getsize!T(t, stack, 0);
866 }
867 
868 //////////////////////////////////////////////////////////////////json///////////////////////////
869 private:
870 enum bool isFloatType(T) = isType!(T, float) || isType!(T, double);
871 
872 JSONValue toJson(T)(T t, RefClass stack, uint level)
873         if (isSignedType!T || isUnsignedType!T || is(T == string) || is(T == bool) || isFloatType!T)
874 {
875     return JSONValue(t);
876 }
877 
878 // uinteger
879 T toObject(T)(JSONValue v, RefClass stack) if (isUnsignedType!T)
880 {
881     if(v.type() == JSONType.uinteger)
882         return cast(T) v.uinteger;
883     else
884         return T.init;
885 }
886 
887 // integer
888 T toObject(T)(JSONValue v, RefClass stack) if (isSignedType!T)
889 {
890     if(v.type() == JSONType.integer)
891         return cast(T) v.integer;
892     else
893         return T.init;
894 }
895 
896 // string
897 T toObject(T)(JSONValue v, RefClass stack) if (is(T == string))
898 {
899     if(v.type() == JSONType..string)
900         return v.str;
901     else
902         return T.init;
903 }
904 
905 // bool
906 T toObject(T)(JSONValue v, RefClass stack) if (is(T == bool))
907 {
908     if(v.type() == JSONType.true_ || v.type() == JSONType.false_)
909         return v.type() == JSONType.true_;
910     else
911         return T.init;
912 }
913 
914 // floating
915 T toObject(T)(JSONValue v, RefClass stack) if (isFloatType!T)
916 {
917     if(v.type() == JSONType.float_)
918         return cast(T) v.floating;
919     else
920         return  T.init;
921 }
922 
923 
924 // array
925 JSONValue toJson(T)(T t, RefClass stack, uint level)
926         if (isStaticArray!T || (isDynamicArray!T && !is(T == string) && !is(T == enum)))
927 {
928     JSONValue[] j;
929     foreach (e; t)
930     {
931         j ~= toJson(e, stack, level);
932     }
933 
934     return JSONValue(j);
935 }
936 
937 T toObject(T)(JSONValue v, RefClass stack) if (isStaticArray!T)
938 {
939     T t;
940     if(v.type() == JSONType.array)
941     {
942         for (size_t i = 0; i < t.length; i++)
943         {
944             t[i] = toObject!(typeof(t[i]))(v.array[i], stack);
945         }
946     }
947     return t;
948     
949 }
950 
951 T toObject(T)(JSONValue v, RefClass stack) if (isDynamicArray!T && !is(T == string)&& !is(T == enum))
952 {
953     T t;
954     if(v.type() == JSONType.array)
955     {
956         t.length = v.array.length;
957         for (size_t i = 0; i < t.length; i++)
958         {
959             t[i] = toObject!(typeof(t[i]))(v.array[i], stack);
960         }
961     }
962     return t;
963 }
964 
965 // struct & class
966 
967 string toJsonMembers(T , bool ignore)()
968 {
969     string str;
970     foreach (m; FieldNameTuple!T)
971     {
972         static if (__traits(getProtection, __traits(getMember, T, m)) == "public")
973         {
974             if(!ignore || !hasUDA!(__traits(getMember , T , m) ,IGNORE ))
975             {
976                 str ~= "j[\"" ~ m ~ "\"] = toJson(t." ~ m ~ " , stack , level + 1);";
977             }    
978         }
979     }
980     return str;
981 }
982 
983 string toJsonMembersAll(T)()
984 {
985     string str;
986     foreach (m; FieldNameTuple!T)
987     {
988         static if (__traits(getProtection, __traits(getMember, T, m)) == "public")
989         {        
990             str ~= "j[\"" ~ m ~ "\"] = toJson(t." ~ m ~ " , stack , level + 1);";
991         }
992     }
993     return str;
994 }
995 
996 
997 
998 string toObjectMembers(T)()
999 {
1000     string str;
1001     foreach (m; FieldNameTuple!T)
1002     {
1003         static if (__traits(getProtection, __traits(getMember, T, m)) == "public")
1004         {
1005             str ~= " if ( \"" ~ m ~ "\"  in j )";
1006             str ~= "t." ~ m ~ " = toObject!(typeof(t." ~ m ~ "))(j[\"" ~ m ~ "\"] , stack);";
1007         }
1008 
1009     }
1010     return str;
1011 }
1012 
1013 JSONValue toJson(T)(T t, RefClass stack, uint level) if (is(T == struct))
1014 {
1015     JSONValue j;
1016 
1017     static if (is(T == JSONValue))
1018     {
1019         return t;
1020     }
1021     else{
1022         bool ignore = (stack.unIgnore is null)? stack.ignore :(stack.unIgnore.ignore!T);
1023 
1024         if(ignore)
1025             mixin(toJsonMembers!(T,true));
1026         else
1027             mixin(toJsonMembers!(T,false));
1028         return j;
1029     }
1030 }
1031 
1032 T toObject(T)(JSONValue j, RefClass stack) if (is(T == struct))
1033 {
1034     static if (is(T == JSONValue))
1035     {
1036         return j;
1037     }
1038     else
1039     {
1040         T t;
1041         if(j.type() == JSONType.object)
1042         {
1043             mixin(toObjectMembers!T);
1044         }
1045         return t;
1046     }
1047 }
1048 
1049 JSONValue toJson(T)(T t, RefClass stack, uint level) if (is(T == class))
1050 {
1051     if (t is null || level >= stack.level)
1052     {
1053         return JSONValue(null);
1054     }
1055 
1056     auto id = t.toHash() in stack.map;
1057     if (id == null)
1058     {
1059         stack.map[t.toHash()] = stack.map.length;
1060         JSONValue j;
1061         bool ignore = (stack.unIgnore is null)? stack.ignore :(stack.unIgnore.ignore!T);
1062 
1063         if(ignore)
1064             mixin(toJsonMembers!(T,true));
1065         else
1066             mixin(toJsonMembers!(T,false));
1067         return j;
1068     }
1069     else
1070     {
1071         JSONValue j;
1072         j[MAGIC_KEY] = *id;
1073         return j;
1074     }
1075 }
1076 
1077 T toObject(T)(JSONValue j, RefClass stack) if (is(T == class))
1078 {
1079     if ( j.type() != JSONType.object)
1080         return T.init;
1081     assert(j.type() == JSONType.object);
1082 
1083     if (MAGIC_KEY in j)
1084     {
1085         return cast(T) stack.arr[j[MAGIC_KEY].uinteger];
1086     }
1087     else
1088     {
1089         T t = new T;
1090         stack.arr ~= cast(void*) t;
1091         mixin(toObjectMembers!T);
1092         return t;
1093     }
1094 }
1095 
1096 //AssociativeArray
1097 JSONValue toJson(T)(T t, RefClass stack, uint level) if (isAssociativeArray!T)
1098 {
1099     JSONValue j;
1100     import std.conv;
1101 
1102     foreach (k, v; t)
1103         j[to!string(k)] = toJson(v, stack, level);
1104     return j;
1105 }
1106 
1107 T toObject(T)(JSONValue j, RefClass stack) if (isAssociativeArray!T)
1108 {
1109     import std.conv;
1110     if ( j.type() != JSONType.object)
1111         return T.init;
1112     T t;
1113     foreach (k, v; j.object)
1114     {
1115         t[to!(KeyType!T)(k)] = toObject!(ValueType!T)(v, stack);
1116     }
1117     return t;
1118 }
1119 
1120 //enum
1121 JSONValue toJson(T)(T t, RefClass stack, uint level) if (is(T == enum))
1122 {
1123     
1124     auto j =  JSONValue(cast(OriginalType!T)t);
1125     writeln(j.type());
1126     return j;
1127 }
1128 
1129 T toObject(T)(JSONValue j, RefClass stack) if (is(T == enum))
1130 {
1131     import std.conv;
1132     writeln(j , " " , j.type() , typeid(T));
1133     OriginalType!T val;
1134     static if (is(OriginalType!T == string ))
1135     {
1136         if(j.type() == JSONType..string)
1137             val = cast(OriginalType!T)j.str;
1138         else
1139             return T.init;
1140     }
1141     else static if (is(OriginalType!T == int))
1142     {
1143         if(j.type() == JSONType.integer)
1144             val = cast(OriginalType!T)j.integer;
1145         else if(j.type() == JSONType.uinteger)
1146             val = cast(OriginalType!T)j.uinteger;
1147         else
1148             return T.init;
1149     }
1150 
1151     return cast(T)val;    
1152 }
1153 
1154 public:
1155 
1156 JSONValue toJson(T)(T t , uint level = uint.max , bool ignore = true)
1157 {
1158     RefClass stack = new RefClass();
1159     stack.level = level;
1160     stack.ignore = ignore;
1161     return toJson!T(t, stack, 0);
1162 }
1163 
1164 JSONValue toJson(T)(T t   , UnIgnoreArray array  ,  uint level = uint.max)
1165 {
1166     RefClass stack = new RefClass();
1167     stack.level = level;
1168     stack.unIgnore = array;
1169     return toJson!T(t, stack, 0);
1170 }
1171 
1172 T toObject(T)(JSONValue j)
1173 {
1174     RefClass stack = new RefClass();
1175     return toObject!T(j, stack);
1176 }
1177 
1178 deprecated("Use toJson instead.")
1179 alias toJSON = toJson;
1180 
1181 deprecated("Using toObject instead.")
1182 alias toOBJ = toObject;
1183 
1184 /// toTextString
1185 /**
1186 Takes a tree of JSON values and returns the serialized string.
1187 
1188 Any Object types will be serialized in a key-sorted order.
1189 
1190 If `pretty` is false no whitespaces are generated.
1191 If `pretty` is true serialized string is formatted to be human-readable.
1192 Set the $(LREF JSONOptions.specialFloatLiterals) flag is set in `options` to encode NaN/Infinity as strings.
1193 */
1194 string toTextString(const ref JSONValue root, in bool pretty = false, in JSONOptions options = JSONOptions.none) @safe
1195 {
1196     import std.array;
1197     import std.conv;
1198     import std.string;
1199 
1200     auto json = appender!string();
1201 
1202     void toStringImpl(Char)(string str) @safe
1203     {
1204         json.put('"');
1205 
1206         foreach (Char c; str)
1207         {
1208             switch (c)
1209             {
1210                 case '"':       json.put("\\\"");       break;
1211                 case '\\':      json.put("\\\\");       break;
1212 
1213                 case '/':
1214                     if (!(options & JSONOptions.doNotEscapeSlashes))
1215                         json.put('\\');
1216                     json.put('/');
1217                     break;
1218 
1219                 case '\b':      json.put("\\b");        break;
1220                 case '\f':      json.put("\\f");        break;
1221                 case '\n':      json.put("\\n");        break;
1222                 case '\r':      json.put("\\r");        break;
1223                 case '\t':      json.put("\\t");        break;
1224                 default:
1225                 {
1226                     import std.ascii : isControl;
1227                     import std.utf : encode;
1228 
1229                     // Make sure we do UTF decoding iff we want to
1230                     // escape Unicode characters.
1231                     assert(((options & JSONOptions.escapeNonAsciiChars) != 0)
1232                         == is(Char == dchar), "JSONOptions.escapeNonAsciiChars needs dchar strings");
1233 
1234                     with (JSONOptions) if (isControl(c) ||
1235                         ((options & escapeNonAsciiChars) >= escapeNonAsciiChars && c >= 0x80))
1236                     {
1237                         // Ensure non-BMP characters are encoded as a pair
1238                         // of UTF-16 surrogate characters, as per RFC 4627.
1239                         wchar[2] wchars; // 1 or 2 UTF-16 code units
1240                         size_t wNum = encode(wchars, c); // number of UTF-16 code units
1241                         foreach (wc; wchars[0 .. wNum])
1242                         {
1243                             json.put("\\u");
1244                             foreach_reverse (i; 0 .. 4)
1245                             {
1246                                 char ch = (wc >>> (4 * i)) & 0x0f;
1247                                 ch += ch < 10 ? '0' : 'A' - 10;
1248                                 json.put(ch);
1249                             }
1250                         }
1251                     }
1252                     else
1253                     {
1254                         json.put(c);
1255                     }
1256                 }
1257             }
1258         }
1259 
1260         json.put('"');
1261     }
1262 
1263     void toString(string str) @safe
1264     {
1265         // Avoid UTF decoding when possible, as it is unnecessary when
1266         // processing JSON.
1267         if (options & JSONOptions.escapeNonAsciiChars)
1268             toStringImpl!dchar(str);
1269         else
1270             toStringImpl!char(str);
1271     }
1272 
1273     void toValue(ref const JSONValue value, ulong indentLevel) @safe
1274     {
1275         void putTabs(ulong additionalIndent = 0)
1276         {
1277             if (pretty)
1278                 foreach (i; 0 .. indentLevel + additionalIndent)
1279                     json.put("    ");
1280         }
1281         void putEOL()
1282         {
1283             if (pretty)
1284                 json.put('\n');
1285         }
1286         void putCharAndEOL(char ch)
1287         {
1288             json.put(ch);
1289             putEOL();
1290         }
1291 
1292         final switch (value.type)
1293         {
1294             case JSONType.object:
1295                 auto obj = value.objectNoRef;
1296                 if (!obj.length)
1297                 {
1298                     json.put("{}");
1299                 }
1300                 else
1301                 {
1302                     putCharAndEOL('{');
1303                     bool first = true;
1304 
1305                     void emit(R)(R names)
1306                     {
1307                         foreach (name; names)
1308                         {
1309                             auto member = obj[name];
1310                             if (!first)
1311                                 putCharAndEOL(',');
1312                             first = false;
1313                             putTabs(1);
1314                             toString(name);
1315                             json.put(':');
1316                             if (pretty)
1317                                 json.put(' ');
1318                             toValue(member, indentLevel + 1);
1319                         }
1320                     }
1321 
1322                     import std.algorithm.sorting : sort;
1323                     // @@@BUG@@@ 14439
1324                     // auto names = obj.keys;  // aa.keys can't be called in @safe code
1325                     auto names = new string[obj.length];
1326                     size_t i = 0;
1327                     foreach (k, v; obj)
1328                     {
1329                         names[i] = k;
1330                         i++;
1331                     }
1332                     sort(names);
1333                     emit(names);
1334 
1335                     putEOL();
1336                     putTabs();
1337                     json.put('}');
1338                 }
1339                 break;
1340 
1341             case JSONType.array:
1342                 auto arr = value.arrayNoRef;
1343                 if (arr.empty)
1344                 {
1345                     json.put("[]");
1346                 }
1347                 else
1348                 {
1349                     putCharAndEOL('[');
1350                     foreach (i, el; arr)
1351                     {
1352                         if (i)
1353                             putCharAndEOL(',');
1354                         putTabs(1);
1355                         toValue(el, indentLevel + 1);
1356                     }
1357                     putEOL();
1358                     putTabs();
1359                     json.put(']');
1360                 }
1361                 break;
1362 
1363             case JSONType..string:
1364                 toString(value.str);
1365                 break;
1366 
1367             case JSONType.integer:
1368                 json.put(to!string(value.integer));
1369                 break;
1370 
1371             case JSONType.uinteger:
1372                 json.put(to!string(value.uinteger));
1373                 break;
1374 
1375             case JSONType.float_:
1376                 import std.math : isNaN, isInfinity;
1377 
1378                 auto val = value.floating;
1379 
1380                 if (val.isNaN)
1381                 {
1382                     if (options & JSONOptions.specialFloatLiterals)
1383                     {
1384                         toString(JSONFloatLiteral.nan);
1385                     }
1386                     else
1387                     {
1388                         throw new JSONException(
1389                             "Cannot encode NaN. Consider passing the specialFloatLiterals flag.");
1390                     }
1391                 }
1392                 else if (val.isInfinity)
1393                 {
1394                     if (options & JSONOptions.specialFloatLiterals)
1395                     {
1396                         toString((val > 0) ?  JSONFloatLiteral.inf : JSONFloatLiteral.negativeInf);
1397                     }
1398                     else
1399                     {
1400                         throw new JSONException(
1401                             "Cannot encode Infinity. Consider passing the specialFloatLiterals flag.");
1402                     }
1403                 }
1404                 else
1405                 {
1406                     import std.format : format;
1407                     // The correct formula for the number of decimal digits needed for lossless round
1408                     // trips is actually:
1409                     //     ceil(Log(pow(2.0, double.mant_dig - 1)) / Log(10.0) + 1) == (double.dig + 2)
1410                     // Anything less will round off (1 + double.epsilon)
1411                     json.put("%s".format(val));
1412                 }
1413                 break;
1414 
1415             case JSONType.true_:
1416                 json.put("true");
1417                 break;
1418 
1419             case JSONType.false_:
1420                 json.put("false");
1421                 break;
1422 
1423             case JSONType.null_:
1424                 json.put("null");
1425                 break;
1426         }
1427     }
1428 
1429     toValue(root, 0);
1430     return json.data;
1431 }
1432 
1433 
1434 /**
1435 */
1436 mixin template SerializationMember(T) {
1437     import std.traits;
1438     debug(GEAR_DEBUG_MORE) import geario.logging;
1439 
1440     alias baseClasses = BaseClassesTuple!T;
1441 
1442     static if(baseClasses.length == 1 && is(baseClasses[0] == Object)) {
1443         ubyte[] Serialize() {
1444             ubyte[] bytes = cast(ubyte[]).serialize!(T, false)(this);
1445             debug(GEAR_DEBUG_MORE) 
1446                 log.trace("this level (%s), length: %d, data: %(%02X %)", T.stringof, bytes.length, bytes);
1447             return bytes;
1448         }
1449         
1450         // void deserialize(ubyte[] data) {
1451 
1452         // }
1453     } else {
1454         // pragma(msg, T.stringof);
1455         override ubyte[] Serialize() {
1456             auto bytes = cast(ubyte[])geario.util.Serialize.serialize!(T, false)(this);
1457             debug(GEAR_DEBUG_MORE) 
1458                 log.trace("current level (%s), length: %d, data: %(%02X %)", T.stringof, bytes.length, bytes);
1459             
1460             ubyte[] data = super.Serialize();
1461             data[1] = cast(ubyte)(data[1] + bytes.length - 2);
1462             data ~= bytes[2..$];
1463             debug(GEAR_DEBUG_MORE) 
1464                 log.trace("all levels (%s), length: %d, data: %(%02X %)", T.stringof, data.length, data);
1465 
1466             // auto bytes = cast(ubyte[])geario.util.Serialize.Serialize(this);
1467             // log.trace("length: %d, data: %(%02X %)", bytes.length, bytes);
1468             return data;
1469         }    
1470 
1471         // override void deserialize(ubyte[] data) {
1472 
1473         // }
1474     }
1475 
1476 
1477 }
1478 
1479 
1480 // only for , nested , new T
1481 /*
1482 version (unittest)
1483 {
1484     //test struct
1485         void test1(T)(T t)
1486         {
1487             assert(unserialize!T(Serialize(t)) == t);
1488             assert(Serialize(t).length == getsize(t));
1489             assert(toObject!T(toJson(t)) == t);
1490         }
1491         struct T1
1492         {
1493             bool b;
1494             byte ib;
1495             ubyte ub;
1496             short ish;
1497             ushort ush;
1498             int ii;
1499             uint ui;
1500             long il;
1501             ulong ul;
1502             string s;
1503             uint[10] sa;
1504             long[] sb;
1505         }
1506         struct T2
1507         {
1508             string n;
1509             T1[] t;
1510         }
1511         struct T3
1512         {
1513             T1 t1;
1514             T2 t2;
1515             string[] name;
1516         }
1517         //test class
1518         class C
1519         {
1520             int age;
1521             string name;
1522             T3 t3;
1523             override bool opEquals(Object c)
1524             {
1525                 auto c1 = cast(C) c;
1526                 return age == c1.age && name == c1.name && t3 == c1.t3;
1527             }
1528             C clone()
1529             {
1530                 auto c = new C();
1531                 c.age = age;
1532                 c.name = name;
1533                 c.t3 = t3;
1534                 return c;
1535             }
1536         }
1537         class C2
1538         {
1539             C[] c;
1540             C c1;
1541             T1 t1;
1542             override bool opEquals(Object c)
1543             {
1544                 auto c2 = cast(C2) c;
1545                 return this.c == c2.c && c1 == c2.c1 && t1 == c2.t1;
1546             }
1547         }
1548         //ref test
1549         class School
1550         {
1551             string name;
1552             User[] users;
1553             override bool opEquals(Object c)
1554             {
1555                 auto school = cast(School) c;
1556                 return school.name == this.name;
1557             }
1558         }
1559         class User
1560         {
1561             int age;
1562             string name;
1563             School school;
1564             override bool opEquals(Object c)
1565             {
1566                 auto user = cast(User) c;
1567                 return user.age == this.age && user.name == this.name && user.school == this.school;
1568             }
1569         }
1570         struct J{
1571             string data;
1572             JSONValue val;
1573         
1574         }
1575 
1576         enum MONTH
1577         {
1578             M1,
1579             M2
1580         }
1581 
1582         enum WEEK : int
1583         {
1584             K1 = 1,
1585             K2 = 2
1586         }
1587 
1588         enum DAY : string
1589         {
1590             D1 = "one",
1591             D2 = "two"
1592         }
1593 
1594         class Date1
1595         {
1596             MONTH month;
1597             WEEK week;
1598             DAY day;
1599             override bool opEquals(Object c)
1600             {
1601                 auto date = cast(Date1) c;
1602                 return date.month == this.month && date.week == this.week && date.day == this.day;
1603             }
1604 
1605         }
1606 
1607         void test_enum_ser()
1608         {
1609             Date1 date = new Date1();
1610             date.month = MONTH.M2;
1611             date.week = WEEK.K2;
1612             date.day = DAY.D2;
1613             test1(date);
1614             
1615         }
1616 
1617         void test_json_ser()
1618         {
1619             J j;
1620             j.data = "test";
1621             j.val = "FUC";
1622             toObject!J(toJson(j));
1623         }
1624         void test_ref_class()
1625         {
1626             School school = new School();
1627             User user1 = new User();
1628             user1.age = 30;
1629             user1.name = "zhangyuchun";
1630             user1.school = school;
1631             User user2 = new User();
1632             user2.age = 31;
1633             user2.name = "wulishan";
1634             user2.school = school;
1635             school.name = "putao";
1636             school.users ~= user1;
1637             school.users ~= user2;
1638             test1(user1);
1639             test1(user2);
1640         }
1641         void test_struct_class_array()
1642         {
1643             T1 t;
1644             t.b = true;
1645             t.ib = -11;
1646             t.ub = 128 + 50;
1647             t.ish = -50;
1648             t.ush = (1 << 15) + 50;
1649             t.ii = -50;
1650             t.ui = (1 << 31) + 50;
1651             t.il = (cast(long) 1 << 63) - 50;
1652             t.ul = (cast(long) 1 << 63) + 50;
1653             t.s = "test";
1654             t.sa[0] = 10;
1655             t.sa[1] = 100;
1656             t.sb ~= 10;
1657             t.sb ~= 100;
1658             test1(t);
1659             T2 t2;
1660             t2.t ~= t;
1661             t2.t ~= t;
1662             t2.n = "testt2";
1663             test1(t2);
1664             T3 t3;
1665             t3.t1 = t;
1666             t3.t2 = t2;
1667             t3.name ~= "123";
1668             t3.name ~= "456";
1669             test1(t3);
1670             C c1 = new C();
1671             c1.age = 100;
1672             c1.name = "test";
1673             c1.t3 = t3;
1674             test1(c1);
1675             C2 c2 = new C2();
1676             c2.c ~= c1;
1677             c2.c ~= c1.clone();
1678             c2.c1 = c1.clone();
1679             c2.t1 = t;
1680             test1(c2);
1681             C2 c3 = null;
1682             test1(c3);
1683             string[string] map1 = ["1" : "1", "2" : "2"];
1684             string[int] map2 = [1 : "1", 2 : "2"];
1685             T1[string] map3;
1686             T1 a1;
1687             a1.ib = 1;
1688             T1 a2;
1689             a2.ib = 2;
1690             map3["1"] = a1;
1691             map3["2"] = a2;
1692             test1(map1);
1693             test1(map2);
1694             test1(map3);
1695         }
1696     
1697 }
1698 unittest
1699 {
1700     import std.stdio;
1701     long index;
1702     void test(T)(T v)
1703     {
1704         long index;
1705         byte[] bs = toVariant(v);
1706         long length = bs.length;
1707         bs ~= ['x', 'y'];
1708         assert(toT!T(bs, index) == v && index == length);
1709         assert(toObject!T(toJson(v)) == v);
1710     }
1711     //test variant
1712     //unsigned
1713     {
1714         ubyte j0 = 0;
1715         ubyte j1 = 50;
1716         ubyte j2 = (1 << 7) + 50;
1717         ubyte j3 = 0xFF;
1718         ushort j4 = (1 << 14) + 50;
1719         ushort j5 = 0xFFFF;
1720         uint j6 = (1 << 21) + 50;
1721         uint j7 = (1 << 28) + 50;
1722         uint j8 = 128;
1723         uint j9 = 0xFFFFFFFF;
1724         {
1725         }
1726         ulong j10 = (cast(ulong) 1 << 35) + 50;
1727         ulong j11 = (cast(ulong) 1 << 42) + 50;
1728         ulong j12 = (cast(ulong) 1 << 49) + 50;
1729         ulong j13 = (cast(ulong) 1 << 56) + 50;
1730         ulong j14 = j9 + j10 + j11 + j12;
1731         ulong j15 = 0xFFFFFFFFFFFFFFFF;
1732         test(j0);
1733         test(j1);
1734         test(j2);
1735         test(j3);
1736         test(j4);
1737         test(j5);
1738         test(j6);
1739         test(j7);
1740         test(j8);
1741         test(j9);
1742         test(j10);
1743         test(j11);
1744         test(j12);
1745         test(j13);
1746         test(j14);
1747         test(j15);
1748     }
1749     //signed
1750     {
1751         byte i0 = 0;
1752         byte i1 = (1 << 6) + 50;
1753         byte i2 = (1 << 7) - 1;
1754         byte i3 = -i2;
1755         byte i4 = -i1;
1756         test(i0);
1757         test(i1);
1758         test(i2);
1759         test(i3);
1760         test(i4);
1761         short i5 = (1 << 7) + 50;
1762         short i6 = (1 << 14) + 50;
1763         short i7 = -i5;
1764         short i8 = -i6;
1765         test(i5);
1766         test(i6);
1767         test(i7);
1768         test(i8);
1769         int i9 = (1 << 16) + 50;
1770         int i10 = (1 << 25) + 50;
1771         int i11 = (1 << 30) + 50;
1772         int i12 = 64;
1773         int i13 = -i10;
1774         int i14 = -i11;
1775         int i15 = i9 + i10 + i11;
1776         int i16 = -i15;
1777         test(i9);
1778         test(i10);
1779         test(i11);
1780         test(i12);
1781         test(i13);
1782         test(i14);
1783         test(i15);
1784         test(i16);
1785         long i17 = (cast(long) 1 << 32) + 50;
1786         long i18 = (cast(long) 1 << 48) + 50;
1787         long i19 = (cast(long) 1 << 63) + 50;
1788         long i20 = i17 + i18 + i19;
1789         long i21 = -i17;
1790         long i22 = -i20;
1791         test(i17);
1792         test(i18);
1793         test(i19);
1794         test(i20);
1795         test(i21);
1796         test(i22);
1797         int i23 = -11;
1798         test(i23);
1799     }
1800     //test serialize
1801     //basic: byte ubyte short ushort int uint long ulong
1802     {
1803         byte b1 = 123;
1804         byte b2 = -11;
1805         ubyte b3 = 233;
1806         short s1 = -11;
1807         short s2 = (1 << 8) + 50;
1808         short s3 = (1 << 15) - 50;
1809         ushort s4 = (1 << 16) - 50;
1810         int i1 = -11;
1811         int i2 = (1 << 16) + 50;
1812         int i3 = (1 << 31) - 50;
1813         uint i4 = (1 << 31) + 50;
1814         long l1 = -11;
1815         long l2 = (cast(long) 1 << 32) + 50;
1816         long l3 = (cast(long) 1 << 63) - 50;
1817         ulong l4 = (cast(long) 1 << 63) + 50;
1818         test1(b1);
1819         test1(b2);
1820         test1(b3);
1821         test1(s1);
1822         test1(s2);
1823         test1(s3);
1824         test1(s4);
1825         test1(i1);
1826         test1(i2);
1827         test1(i3);
1828         test1(i4);
1829         test1(l1);
1830         test1(l2);
1831         test1(l3);
1832         test1(l4);
1833     }
1834     //test string
1835     {
1836         string s1 = "";
1837         string s2 = "1";
1838         string s3 = "123";
1839         test1(s1);
1840         test1(s2);
1841         test1(s3);
1842     }
1843     //test static arrary
1844     {
1845         string[5] sa;
1846         sa[0] = "test0";
1847         sa[1] = "test1";
1848         sa[2] = "test2";
1849         sa[3] = "test3";
1850         sa[4] = "test4";
1851         test1(sa);
1852     }
1853     //test dynamic arrary
1854     {
1855         string[] sa;
1856         sa ~= "test1";
1857         sa ~= "test2";
1858         sa ~= "test3";
1859         sa ~= "test4";
1860         test1(sa);
1861         string[] sa2;
1862         test1(sa2);
1863     }
1864     //test enum \ struct \ class \ associative array
1865     test_enum_ser();
1866     test_struct_class_array();
1867     test_ref_class();
1868     test_json_ser();
1869     ////unsigned
1870         uint ut1 = 1 << 7;
1871         uint ut2 = 1 << 14;
1872         uint ut3 = 1 << 21;
1873         uint ut4 = 1 << 28;
1874 //signed
1875         int it1 = 1 << 6;
1876         int it2 = 1 << 13;
1877         int it3 = 1 << 20;
1878         int it4 = 1 << 27;
1879         test1(ut1);
1880         test1(ut2);
1881         test1(ut3);
1882         test1(ut4);
1883         test1(it1);
1884         test1(it2);
1885         test1(it3);
1886         test1(it4);
1887 }
1888 */