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