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 
13 deprecated("It's buggy. Use hunt.serialization.JsonSerializer instead.")
14 module hunt.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 in 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(HUNT_DEBUG_MORE) import hunt.logging.ConsoleLogger;
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(HUNT_DEBUG_MORE) 
1446 				tracef("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[])hunt.util.Serialize.serialize!(T, false)(this);
1457             debug(HUNT_DEBUG_MORE) 
1458 				tracef("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(HUNT_DEBUG_MORE) 
1464 				tracef("all levels (%s), length: %d, data: %(%02X %)", T.stringof, data.length, data);
1465 
1466             // auto bytes = cast(ubyte[])hunt.util.Serialize.serialize(this);
1467             // tracef("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 */