1 // Written in the D programming language.
2 
3 /**
4  * MessagePack serializer and deserializer implementation.
5  *
6  * MessagePack is a binary-based serialization specification.
7  *
8  * Example:
9  * -----
10  * auto data = tuple("MessagePack!", [1, 2], true);
11  *
12  * auto serialized = pack(data);
13  *
14  * // ...
15  *
16  * typeof(data) deserialized;
17  *
18  * unpack(serialized, deserialized);
19  *
20  * assert(data == deserialized);
21  * -----
22  *
23  * See_Also:
24  *  $(LINK2 http://msgpack.org/, The MessagePack Project)$(BR)
25  *  $(LINK2 http://wiki.msgpack.org/display/MSGPACK/Design+of+Serialization, MessagePack Design concept)$(BR)
26  *  $(LINK2 http://wiki.msgpack.org/display/MSGPACK/Format+specification, MessagePack data format)
27  *
28  * Copyright: Copyright Masahiro Nakagawa 2010-.
29  * License:   <a href="http://www.boost.org/LICENSE_1_0.txt">Boost License 1.0</a>.
30  * Authors:   Masahiro Nakagawa
31  */
32 module bio.bam.thirdparty.msgpack;
33 
34 import std.array;
35 import std.exception;
36 import std.range;
37 import std.stdio;
38 import std.traits;
39 import std.typecons;
40 import std.typetuple;
41 
42 // for RefBuffer
43 version(Posix)
44 {
45     import core.sys.posix.sys.uio : iovec;
46 }
47 else
48 {
49     /**
50      * from core.sys.posix.sys.uio.iovec for compatibility with posix.
51      */
52     struct iovec
53     {
54         void*  iov_base;
55         size_t iov_len;
56     }
57 }
58 
59 // for Converting Endian using ntohs and ntohl;
60 version(Windows)
61 {
62     import core.stdc.windows.winsock;
63 }
64 else
65 {
66     import core.sys.posix.arpa.inet;
67 }
68 
69 version(EnableReal)
70 {
71     enum EnableReal = true;
72 }
73 else
74 {
75     enum EnableReal = false;
76 }
77 
78 static if (real.sizeof == double.sizeof) {
79     // for 80bit real inter-operation on non-x86 CPU
80     version = NonX86;
81 
82     import std.numeric;
83 }
84 
85 version(unittest) import std.file, core.stdc.string;
86 
87 
88 @trusted:
89 
90 
91 public:
92 
93 
94 // Convenient functions
95 
96 
97 /**
98  * Serializes $(D_PARAM args).
99  *
100  * Assumes single object if the length of $(D_PARAM args) == 1,
101  * otherwise array object.
102  *
103  * Params:
104  *  args = the contents to serialize.
105  *
106  * Returns:
107  *  a serialized data.
108  */
109 ubyte[] pack(bool withFieldName = false, Args...)(in Args args)
110 {
111     auto packer = Packer(withFieldName);
112 
113     static if (Args.length == 1)
114         packer.pack(args[0]);
115     else
116         packer.packArray(args);
117 
118     return packer.stream.data;
119 }
120 
121 
122 unittest
123 {
124     auto serialized = pack(false);
125 
126     assert(serialized[0] == Format.FALSE);
127 
128     auto deserialized = unpack(pack(1, true, "Foo"));
129 
130     assert(deserialized.type == Value.Type.array);
131     assert(deserialized.via.array[0].type == Value.Type.unsigned);
132     assert(deserialized.via.array[1].type == Value.Type.boolean);
133     assert(deserialized.via.array[2].type == Value.Type.raw);
134 }
135 
136 
137 /**
138  * Deserializes $(D_PARAM buffer) using stream deserializer.
139  *
140  * Params:
141  *  buffer = the buffer to deserialize.
142  *
143  * Returns:
144  *  a $(D Unpacked) contains deserialized object.
145  *
146  * Throws:
147  *  UnpackException if deserialization doesn't succeed.
148  */
149 Unpacked unpack(in ubyte[] buffer)
150 {
151     auto unpacker = StreamingUnpacker(buffer);
152 
153     if (!unpacker.execute())
154         throw new UnpackException("Deserialization failure");
155 
156     return unpacker.unpacked;
157 }
158 
159 
160 /**
161  * Deserializes $(D_PARAM buffer) using direct-conversion deserializer.
162  *
163  * Assumes single object if the length of $(D_PARAM args) == 1,
164  * otherwise array object.
165  *
166  * Params:
167  *  buffer = the buffer to deserialize.
168  *  args   = the references of values to assign.
169  */
170 void unpack(bool withFieldName = false, Args...)(in ubyte[] buffer, ref Args args)
171 {
172     auto unpacker = Unpacker(buffer, buffer.length, withFieldName);
173 
174     static if (Args.length == 1)
175         unpacker.unpack(args[0]);
176     else
177         unpacker.unpackArray(args);
178 }
179 
180 
181 /**
182  * Return value version
183  */
184 Type unpack(Type, bool withFieldName = false)(in ubyte[] buffer)
185 {
186     auto unpacker = Unpacker(buffer, buffer.length, withFieldName);
187 
188     Type result;
189     unpacker.unpack(result);
190     return result;
191 }
192 
193 
194 unittest
195 {
196     { // stream
197         auto result = unpack(pack(false));
198 
199         assert(result.via.boolean == false);
200     }
201     { // direct conversion
202         Tuple!(uint, string) result;
203         Tuple!(uint, string) test = tuple(1, "Hi!");
204 
205         unpack(pack(test), result);
206         assert(result == test);
207 
208         test.field[0] = 2;
209         test.field[1] = "Hey!";
210         unpack(pack(test.field[0], test.field[1]), result.field[0], result.field[1]);
211         assert(result == test);
212     }
213     { // return value direct conversion
214         Tuple!(uint, string) test = tuple(1, "Hi!");
215 
216         auto data = pack(test);
217         assert(data.unpack!(Tuple!(uint, string)) == test);
218     }
219     { // serialize object as a Map
220         static class C
221         {
222             int num;
223 
224             this(int num) { this.num = num; }
225         }
226 
227         auto test = new C(10);
228         auto result = new C(100);
229 
230         unpack!(true)(pack!(true)(test), result);
231         assert(result.num == 10, "Unpacking with field names failed");
232     }
233 }
234 
235 
236 unittest
237 {
238     // unittest for https://github.com/msgpack/msgpack-d/issues/8
239     foreach (Type; TypeTuple!(byte, short, int, long)) {
240         foreach (i; [-33, -20, -1, 0, 1, 20, 33]) {
241             Type a = cast(Type)i;
242             Type b;
243             unpack(pack(a), b);
244             assert(a == b);
245         }
246     }
247 }
248 
249 
250 /**
251  * $(D MessagePackException) is a root Exception for MessagePack related operation.
252  */
253 class MessagePackException : Exception
254 {
255     pure this(string message)
256     {
257         super(message);
258     }
259 }
260 
261 
262 /**
263  * Attribute for specifying non pack/unpack field.
264  * This is an alternative approach of MessagePackable mixin.
265  *
266  * Example:
267  * -----
268  * struct S
269  * {
270  *     int num;
271  *     // Packer/Unpacker ignores this field;
272  *     @nonPacked string str;
273  * }
274  * -----
275  */
276 struct nonPacked {}
277 
278 template isPackedField(alias field)
279 {
280     enum isPackedField = (staticIndexOf!(nonPacked, __traits(getAttributes, field)) == -1) && (!isSomeFunction!(typeof(field)));
281 }
282 
283 
284 // Serializing routines
285 
286 
287 /**
288  * $(D Packer) is a $(D MessagePack) serializer
289  *
290  * Example:
291  * -----
292  * auto packer = packer(Appender!(ubyte[])());
293  *
294  * packer.packArray(false, 100, 1e-10, null);
295  *
296  * stdout.rawWrite(packer.buffer.data);
297  * -----
298  *
299  * NOTE:
300  *  Current implementation can't deal with a circular reference.
301  *  If you try to serialize a object that has circular reference, runtime raises 'Stack Overflow'.
302  */
303 struct PackerImpl(Stream) if (isOutputRange!(Stream, ubyte) && isOutputRange!(Stream, ubyte[]))
304 {
305   private:
306     static @system
307     {
308         alias void delegate(ref PackerImpl, void*) PackHandler;
309         PackHandler[TypeInfo] packHandlers;
310 
311         public void registerHandler(T, alias Handler)()
312         {
313             packHandlers[typeid(T)] = delegate(ref PackerImpl packer, void* obj) {
314                 Handler(packer, *cast(T*)obj);
315             };
316         }
317     }
318 
319     enum size_t Offset = 1;  // type-information offset
320 
321     Stream                   stream_;  // the stream to write
322     ubyte[Offset + RealSize] store_;   // stores serialized value
323     bool                     withFieldName_;
324 
325 
326   public:
327     /**
328      * Constructs a packer with $(D_PARAM stream).
329      *
330      * Params:
331      *  stream        = the stream to write.
332      *  withFieldName = serialize class / struct with field name
333      */
334     this(Stream stream, bool withFieldName = false)
335     {
336         stream_        = stream;
337         withFieldName_ = withFieldName;
338     }
339 
340 
341     /**
342      * Constructs a packer with $(D_PARAM withFieldName).
343      *
344      * Params:
345      *  withFieldName = serialize class / struct with field name
346      */
347     this(bool withFieldName)
348     {
349         withFieldName_ = withFieldName;
350     }
351 
352 
353     /**
354      * Forwards to stream.
355      *
356      * Returns:
357      *  the stream.
358      */
359     @property @safe
360     nothrow ref Stream stream()
361     {
362         return stream_;
363     }
364 
365 
366     /**
367      * Serializes argument and writes to stream.
368      *
369      * If the argument is the pointer type, dereferences the pointer and serializes pointed value.
370      * -----
371      * int  a = 10;
372      * int* b = &b;
373      *
374      * packer.pack(b);  // serializes 10, not address of a
375      * -----
376      * Serializes nil if the argument of nullable type is null.
377      *
378      * NOTE:
379      *  MessagePack doesn't define $(D_KEYWORD real) type format.
380      *  Don't serialize $(D_KEYWORD real) if you communicate with other languages.
381      *  Transfer $(D_KEYWORD double) serialization if $(D_KEYWORD real) on your environment equals $(D_KEYWORD double).
382      *
383      * Params:
384      *  value = the content to serialize.
385      *
386      * Returns:
387      *  self, i.e. for method chaining.
388      */
389     ref PackerImpl pack(T)(in T value) if (is(Unqual!T == bool))
390     {
391         if (value)
392             stream_.put(Format.TRUE);
393         else
394             stream_.put(Format.FALSE);
395 
396         return this;
397     }
398 
399 
400     /// ditto
401     ref PackerImpl pack(T)(in T value) if (isUnsigned!T && !is(Unqual!T == enum))
402     {
403         // ulong < ulong is slower than uint < uint
404         static if (!is(Unqual!T  == ulong)) {
405             enum Bits = T.sizeof * 8;
406 
407             if (value < (1 << 8)) {
408                 if (value < (1 << 7)) {
409                     // fixnum
410                     stream_.put(take8from!Bits(value));
411                 } else {
412                     // uint 8
413                     store_[0] = Format.UINT8;
414                     store_[1] = take8from!Bits(value);
415                     stream_.put(store_[0..Offset + ubyte.sizeof]);
416                 }
417             } else {
418                 if (value < (1 << 16)) {
419                     // uint 16
420                     const temp = convertEndianTo!16(value);
421 
422                     store_[0] = Format.UINT16;
423                     *cast(ushort*)&store_[Offset] = temp;
424                     stream_.put(store_[0..Offset + ushort.sizeof]);
425                 } else {
426                     // uint 32
427                     const temp = convertEndianTo!32(value);
428 
429                     store_[0] = Format.UINT32;
430                     *cast(uint*)&store_[Offset] = temp;
431                     stream_.put(store_[0..Offset + uint.sizeof]);
432                 }
433             }
434         } else {
435             if (value < (1UL << 8)) {
436                 if (value < (1UL << 7)) {
437                     // fixnum
438                     stream_.put(take8from!64(value));
439                 } else {
440                     // uint 8
441                     store_[0] = Format.UINT8;
442                     store_[1] = take8from!64(value);
443                     stream_.put(store_[0..Offset + ubyte.sizeof]);
444                 }
445             } else {
446                 if (value < (1UL << 16)) {
447                     // uint 16
448                     const temp = convertEndianTo!16(value);
449 
450                     store_[0] = Format.UINT16;
451                     *cast(ushort*)&store_[Offset] = temp;
452                     stream_.put(store_[0..Offset + ushort.sizeof]);
453                 } else if (value < (1UL << 32)){
454                     // uint 32
455                     const temp = convertEndianTo!32(value);
456 
457                     store_[0] = Format.UINT32;
458                     *cast(uint*)&store_[Offset] = temp;
459                     stream_.put(store_[0..Offset + uint.sizeof]);
460                 } else {
461                     // uint 64
462                     const temp = convertEndianTo!64(value);
463 
464                     store_[0] = Format.UINT64;
465                     *cast(ulong*)&store_[Offset] = temp;
466                     stream_.put(store_[0..Offset + ulong.sizeof]);
467                 }
468             }
469         }
470 
471         return this;
472     }
473 
474 
475     /// ditto
476     ref PackerImpl pack(T)(in T value) if (isSigned!T && isIntegral!T && !is(Unqual!T == enum))
477     {
478         // long < long is slower than int < int
479         static if (!is(Unqual!T == long)) {
480             enum Bits = T.sizeof * 8;
481 
482             if (value < -(1 << 5)) {
483                 if (value < -(1 << 15)) {
484                     // int 32
485                     const temp = convertEndianTo!32(value);
486 
487                     store_[0] = Format.INT32;
488                     *cast(int*)&store_[Offset] = temp;
489                     stream_.put(store_[0..Offset + int.sizeof]);
490                 } else if (value < -(1 << 7)) {
491                     // int 16
492                     const temp = convertEndianTo!16(value);
493 
494                     store_[0] = Format.INT16;
495                     *cast(short*)&store_[Offset] = temp;
496                     stream_.put(store_[0..Offset + short.sizeof]);
497                 } else {
498                     // int 8
499                     store_[0] = Format.INT8;
500                     store_[1] = take8from!Bits(value);
501                     stream_.put(store_[0..Offset + byte.sizeof]);
502                 }
503             } else if (value < (1 << 7)) {
504                 // fixnum
505                 stream_.put(take8from!Bits(value));
506             } else {
507                 if (value < (1 << 8)) {
508                     // uint 8
509                     store_[0] = Format.UINT8;
510                     store_[1] = take8from!Bits(value);
511                     stream_.put(store_[0..Offset + ubyte.sizeof]);
512                 } else if (value < (1 << 16)) {
513                     // uint 16
514                     const temp = convertEndianTo!16(value);
515 
516                     store_[0] = Format.UINT16;
517                     *cast(ushort*)&store_[Offset] = temp;
518                     stream_.put(store_[0..Offset + ushort.sizeof]);
519                 } else {
520                     // uint 32
521                     const temp = convertEndianTo!32(value);
522 
523                     store_[0] = Format.UINT32;
524                     *cast(uint*)&store_[Offset] = temp;
525                     stream_.put(store_[0..Offset + uint.sizeof]);
526                 }
527             }
528         } else {
529             if (value < -(1L << 5)) {
530                 if (value < -(1L << 15)) {
531                     if (value < -(1L << 31)) {
532                         // int 64
533                         const temp = convertEndianTo!64(value);
534 
535                         store_[0] = Format.INT64;
536                         *cast(long*)&store_[Offset] = temp;
537                         stream_.put(store_[0..Offset + long.sizeof]);
538                     } else {
539                         // int 32
540                         const temp = convertEndianTo!32(value);
541 
542                         store_[0] = Format.INT32;
543                         *cast(int*)&store_[Offset] = temp;
544                         stream_.put(store_[0..Offset + int.sizeof]);
545                     }
546                 } else {
547                     if (value < -(1L << 7)) {
548                         // int 16
549                         const temp = convertEndianTo!16(value);
550 
551                         store_[0] = Format.INT16;
552                         *cast(short*)&store_[Offset] = temp;
553                         stream_.put(store_[0..Offset + short.sizeof]);
554                     } else {
555                         // int 8
556                         store_[0] = Format.INT8;
557                         store_[1] = take8from!64(value);
558                         stream_.put(store_[0..Offset + byte.sizeof]);
559                     }
560                 }
561             } else if (value < (1L << 7)) {
562                 // fixnum
563                 stream_.put(take8from!64(value));
564             } else {
565                 if (value < (1L << 16)) {
566                     if (value < (1L << 8)) {
567                         // uint 8
568                         store_[0] = Format.UINT8;
569                         store_[1] = take8from!64(value);
570                         stream_.put(store_[0..Offset + ubyte.sizeof]);
571                     } else {
572                         // uint 16
573                         const temp = convertEndianTo!16(value);
574 
575                         store_[0] = Format.UINT16;
576                         *cast(ushort*)&store_[Offset] = temp;
577                         stream_.put(store_[0..Offset + ushort.sizeof]);
578                     }
579                 } else {
580                     if (value < (1L << 32)) {
581                         // uint 32
582                         const temp = convertEndianTo!32(value);
583 
584                         store_[0] = Format.UINT32;
585                         *cast(uint*)&store_[Offset] = temp;
586                         stream_.put(store_[0..Offset + uint.sizeof]);
587                     } else {
588                         // uint 64
589                         const temp = convertEndianTo!64(value);
590 
591                         store_[0] = Format.UINT64;
592                         *cast(ulong*)&store_[Offset] = temp;
593                         stream_.put(store_[0..Offset + ulong.sizeof]);
594                     }
595                 }
596             }
597         }
598 
599         return this;
600     }
601 
602 
603     /// ditto
604     ref PackerImpl pack(T)(in T value) if (isFloatingPoint!T && !is(Unqual!T == enum))
605     {
606         static if (is(Unqual!T == float)) {
607             const temp = convertEndianTo!32(_f(value).i);
608 
609             store_[0] = Format.FLOAT;
610             *cast(uint*)&store_[Offset] = temp;
611             stream_.put(store_[0..Offset + uint.sizeof]);
612         } else static if (is(Unqual!T == double)) {
613             const temp = convertEndianTo!64(_d(value).i);
614 
615             store_[0] = Format.DOUBLE;
616             *cast(ulong*)&store_[Offset] = temp;
617             stream_.put(store_[0..Offset + ulong.sizeof]);
618         } else {
619             static if ((real.sizeof > double.sizeof) && EnableReal) {
620                 store_[0]      = Format.REAL;
621                 const temp     = _r(value);
622                 const fraction = convertEndianTo!64(temp.fraction);
623                 const exponent = convertEndianTo!16(temp.exponent);
624 
625                 *cast(Unqual!(typeof(fraction))*)&store_[Offset]                   = fraction;
626                 *cast(Unqual!(typeof(exponent))*)&store_[Offset + fraction.sizeof] = exponent;
627                 stream_.put(store_[0..$]);
628             } else {  // Non-x86 CPUs, real type equals double type.
629                 pack(cast(double)value);
630             }
631         }
632 
633         return this;
634     }
635 
636 
637     /// ditto
638     ref PackerImpl pack(T)(in T value) if (is(Unqual!T == enum))
639     {
640         pack(cast(OriginalType!T)value);
641 
642         return this;
643     }
644 
645 
646     /// Overload for pack(null) for 2.057 or later
647     static if (!is(typeof(null) == void*))
648     {
649         ref PackerImpl pack(T)(in T value) if (is(Unqual!T == typeof(null)))
650         {
651             return packNil();
652         }
653     }
654 
655 
656     /// ditto
657     ref PackerImpl pack(T)(in T value) if (isPointer!T)
658     {
659         static if (is(Unqual!T == void*)) {  // for pack(null) for 2.056 or earlier
660             enforce(value is null, "Can't serialize void type");
661             stream_.put(Format.NIL);
662         } else {
663             if (value is null)
664                 stream_.put(Format.NIL);
665             else
666                 pack(mixin(AsteriskOf!T ~ "value"));
667         }
668 
669         return this;
670     }
671 
672 
673     /// ditto
674     ref PackerImpl pack(T)(in T array) if (isArray!T)
675     {
676         alias typeof(T.init[0]) U;
677 
678         /*
679          * Serializes raw type-information to stream.
680          */
681         void beginRaw(in size_t length)
682         {
683             if (length < 32) {
684                 const ubyte temp = Format.RAW | cast(ubyte)length;
685                 stream_.put(take8from(temp));
686             } else if (length < 65536) {
687                 const temp = convertEndianTo!16(length);
688 
689                 store_[0] = Format.RAW16;
690                 *cast(ushort*)&store_[Offset] = temp;
691                 stream_.put(store_[0..Offset + ushort.sizeof]);
692             } else {
693                 const temp = convertEndianTo!32(length);
694 
695                 store_[0] = Format.RAW32;
696                 *cast(uint*)&store_[Offset] = temp;
697                 stream_.put(store_[0..Offset + uint.sizeof]);
698             }
699         }
700 
701         if (array.empty)
702             return packNil();
703 
704         // Raw bytes
705         static if (isByte!(U) || isSomeChar!(U)) {
706             ubyte[] raw = cast(ubyte[])array;
707 
708             beginRaw(raw.length);
709             stream_.put(raw);
710         } else {
711             beginArray(array.length);
712             foreach (elem; array)
713                 pack(elem);
714         }
715 
716         return this;
717     }
718 
719 
720     /// ditto
721     ref PackerImpl pack(T)(in T array) if (isAssociativeArray!T)
722     {
723         if (array is null)
724             return packNil();
725 
726         beginMap(array.length);
727         foreach (key, value; array) {
728             pack(key);
729             pack(value);
730         }
731 
732         return this;
733     }
734 
735 
736     /// ditto
737     ref PackerImpl pack(Types...)(auto ref const Types objects) if (Types.length > 1)
738     {
739         foreach (i, T; Types)
740             pack(objects[i]);
741 
742         return this;
743     }
744 
745 
746     /**
747      * Serializes $(D_PARAM object) and writes to stream.
748      *
749      * Calling $(D toMsgpack) if $(D_KEYWORD class) and $(D_KEYWORD struct) implement $(D toMsgpack) method. $(D toMsgpack) signature is:
750      * -----
751      * void toMsgpack(Packer)(ref Packer packer) const
752      * -----
753      * This method serializes all members of T object if $(D_KEYWORD class) and $(D_KEYWORD struct) don't implement $(D toMsgpack).
754      *
755      * An object that doesn't implement $(D toMsgpack) is serialized to Array type.
756      * -----
757      * packer.pack(tuple(true, 1, "Hi!"))  // -> '[true, 1, "Hi!"]', not 'ture, 1, "Hi!"'
758      *
759      * struct Foo
760      * {
761      *     int num    = 10;
762      *     string msg = "D!";
763      * }
764      * packer.pack(Foo());  // -> '[10, "D!"]'
765      *
766      * class Base
767      * {
768      *     bool flag = true;
769      * }
770      * class Derived : Base
771      * {
772      *     double = 0.5f;
773      * }
774      * packer.pack(new Derived());  // -> '[true, 0.5f]'
775      * -----
776      *
777      * Params:
778      *  object = the content to serialize.
779      *
780      * Returns:
781      *  self, i.e. for method chaining.
782      */
783     ref PackerImpl pack(T)(in T object) if (is(Unqual!T == class))
784     {
785         if (object is null)
786             return packNil();
787 
788         static if (hasMember!(T, "toMsgpack"))
789         {
790             static if (__traits(compiles, { T t; t.toMsgpack(this, withFieldName_); })) {
791                 object.toMsgpack(this, withFieldName_);
792             } else static if (__traits(compiles, { T t; t.toMsgpack(this); })) { // backward compatible
793                 object.toMsgpack(this);
794             } else {
795                 static assert(0, "Failed to invoke 'toMsgpack' on type '" ~ Unqual!T.stringof ~ "'");
796             }
797         } else {
798             if (auto handler = object.classinfo in packHandlers) {
799                 (*handler)(this, cast(void*)&object);
800                 return this;
801             }
802             if (T.classinfo !is object.classinfo) {
803                 throw new MessagePackException("Can't pack derived class through reference to base class.");
804             }
805 
806             alias SerializingClasses!(T) Classes;
807 
808             immutable memberNum = SerializingMemberNumbers!(Classes);
809             if (withFieldName_)
810                 beginMap(memberNum);
811             else
812                 beginArray(memberNum);
813 
814             foreach (Class; Classes) {
815                 Class obj = cast(Class)object;
816                 if (withFieldName_) {
817                     foreach (i, f ; obj.tupleof) {
818                         static if (isPackedField!(Class.tupleof[i])) {
819                             pack(getFieldName!(Class, i));
820                             pack(f);
821                         }
822                     }
823                 } else {
824                     foreach (i, f ; obj.tupleof) {
825                         static if (isPackedField!(Class.tupleof[i]))
826                             pack(f);
827                     }
828                 }
829             }
830         }
831 
832         return this;
833     }
834 
835 
836     /// ditto
837     @trusted
838     ref PackerImpl pack(T)(auto ref T object) if (is(Unqual!T == struct))
839     {
840         static if (hasMember!(T, "toMsgpack"))
841         {
842             static if (__traits(compiles, { T t; t.toMsgpack(this, withFieldName_); })) {
843                 object.toMsgpack(this, withFieldName_);
844             } else static if (__traits(compiles, { T t; t.toMsgpack(this); })) { // backward compatible
845                 object.toMsgpack(this);
846             } else {
847                 static assert(0, "Failed to invoke 'toMsgpack' on type '" ~ Unqual!T.stringof ~ "'");
848             }
849         } else static if (isTuple!T) {
850             beginArray(object.field.length);
851             foreach (f; object.field)
852                 pack(f);
853         } else {  // simple struct
854             if (auto handler = typeid(T) in packHandlers) {
855                 (*handler)(this, cast(void*)&object);
856                 return this;
857             }
858 
859             immutable memberNum = SerializingMemberNumbers!(T);
860             if (withFieldName_)
861                 beginMap(memberNum);
862             else
863                 beginArray(memberNum);
864 
865             if (withFieldName_) {
866                 foreach (i, f; object.tupleof) {
867                     static if (isPackedField!(T.tupleof[i]) && __traits(compiles, { pack(f); }))
868                     {
869                         pack(getFieldName!(T, i));
870                         pack(f);
871                     }
872                 }
873             } else {
874                 foreach (i, f; object.tupleof) {
875                     static if (isPackedField!(T.tupleof[i]) && __traits(compiles, { pack(f); }))
876                         pack(f);
877                 }
878             }
879         }
880 
881         return this;
882     }
883 
884 
885     /**
886      * Serializes the arguments as container to stream.
887      *
888      * -----
889      * packer.packArray(true, 1);  // -> [true, 1]
890      * packer.packMap("Hi", 100);  // -> ["Hi":100]
891      * -----
892      *
893      * In packMap, the number of arguments must be even.
894      *
895      * Params:
896      *  objects = the contents to serialize.
897      *
898      * Returns:
899      *  self, i.e. for method chaining.
900      */
901     ref PackerImpl packArray(Types...)(auto ref const Types objects)
902     {
903         beginArray(Types.length);
904         foreach (i, T; Types)
905             pack(objects[i]);
906         //pack(objects);  // slow :(
907 
908         return this;
909     }
910 
911 
912     /// ditto
913     ref PackerImpl packMap(Types...)(auto ref const Types objects)
914     {
915         static assert(Types.length % 2 == 0, "The number of arguments must be even");
916 
917         beginMap(Types.length / 2);
918         foreach (i, T; Types)
919             pack(objects[i]);
920 
921         return this;
922     }
923 
924 
925     /**
926      * Serializes the type-information to stream.
927      *
928      * These methods don't serialize contents.
929      * You need to call pack method to serialize contents at your own risk.
930      * -----
931      * packer.beginArray(3).pack(true, 1);  // -> [true, 1,
932      *
933      * // other operation
934      *
935      * packer.pack("Hi!");                  // -> [true, 1, "Hi!"]
936      * -----
937      *
938      * Params:
939      *  length = the length of container.
940      *
941      * Returns:
942      *  self, i.e. for method chaining.
943      */
944     ref PackerImpl beginArray(in size_t length)
945     {
946         if (length < 16) {
947             const ubyte temp = Format.ARRAY | cast(ubyte)length;
948             stream_.put(take8from(temp));
949         } else if (length < 65536) {
950             const temp = convertEndianTo!16(length);
951 
952             store_[0] = Format.ARRAY16;
953             *cast(ushort*)&store_[Offset] = temp;
954             stream_.put(store_[0..Offset + ushort.sizeof]);
955         } else {
956             const temp = convertEndianTo!32(length);
957 
958             store_[0] = Format.ARRAY32;
959             *cast(uint*)&store_[Offset] = temp;
960             stream_.put(store_[0..Offset + uint.sizeof]);
961         }
962 
963         return this;
964     }
965 
966 
967     /// ditto
968     ref PackerImpl beginMap(in size_t length)
969     {
970         if (length < 16) {
971             const ubyte temp = Format.MAP | cast(ubyte)length;
972             stream_.put(take8from(temp));
973         } else if (length < 65536) {
974             const temp = convertEndianTo!16(length);
975 
976             store_[0] = Format.MAP16;
977             *cast(ushort*)&store_[Offset] = temp;
978             stream_.put(store_[0..Offset + ushort.sizeof]);
979         } else {
980             const temp = convertEndianTo!32(length);
981 
982             store_[0] = Format.MAP32;
983             *cast(uint*)&store_[Offset] = temp;
984             stream_.put(store_[0..Offset + uint.sizeof]);
985         }
986 
987         return this;
988     }
989 
990 
991   private:
992     /*
993      * Serializes the nil value.
994      */
995     ref PackerImpl packNil()
996     {
997         stream_.put(Format.NIL);
998         return this;
999     }
1000 }
1001 
1002 
1003 /// Default serializer
1004 alias PackerImpl!(Appender!(ubyte[])) Packer;  // should be pure struct?
1005 
1006 
1007 /**
1008  * Register a serialization handler for $(D_PARAM T) type
1009  *
1010  * Example:
1011  * -----
1012  * registerPackHandler!(Foo, fooPackHandler);
1013  * -----
1014  */
1015 void registerPackHandler(T, alias Handler, Stream = Appender!(ubyte[]))()
1016 {
1017     PackerImpl!(Stream).registerHandler!(T, Handler);
1018 }
1019 
1020 
1021 /**
1022  * Helper for $(D Packer) construction.
1023  *
1024  * Params:
1025  *  stream = the stream to write.
1026  *  withFieldName = serialize class / struct with field name
1027  *
1028  * Returns:
1029  *  a $(D Packer) object instantiated and initialized according to the arguments.
1030  */
1031 PackerImpl!(Stream) packer(Stream)(Stream stream, bool withFieldName = false)
1032 {
1033     return typeof(return)(stream, withFieldName);
1034 }
1035 
1036 
1037 // Buffer implementations
1038 
1039 
1040 /**
1041  * $(D RefBuffer) is a reference stored buffer for more efficient serialization
1042  *
1043  * Example:
1044  * -----
1045  * auto packer = packer(RefBuffer(16));  // threshold is 16
1046  *
1047  * // packs data
1048  *
1049  * writev(fd, cast(void*)packer.buffer.vector.ptr, packer.buffer.vector.length);
1050  * -----
1051  */
1052 struct RefBuffer
1053 {
1054   private:
1055     static struct Chunk
1056     {
1057         ubyte[] data;  // storing serialized value
1058         size_t  used;  // used size of data
1059     }
1060 
1061     immutable size_t Threshold;
1062     immutable size_t ChunkSize;
1063 
1064     // for putCopy
1065     Chunk[] chunks_;  // memory chunk for buffer
1066     size_t  index_;   // index for cunrrent chunk
1067 
1068     // for putRef
1069     iovec[] vecList_;  // reference to large data or copied data.
1070 
1071 
1072   public:
1073     /**
1074      * Constructs a buffer.
1075      *
1076      * Params:
1077      *  threshold = the threshold of writing value or stores reference.
1078      *  chunkSize = the default size of chunk for allocation.
1079      */
1080     @safe
1081     this(in size_t threshold, in size_t chunkSize = 8192)
1082     {
1083         Threshold = threshold;
1084         ChunkSize = chunkSize;
1085 
1086         chunks_.length = 1;
1087         chunks_[index_].data.length = chunkSize;
1088     }
1089 
1090 
1091     /**
1092      * Returns the buffer contents that excluding references.
1093      *
1094      * Returns:
1095      *  the non-contiguous copied contents.
1096      */
1097     @property @safe
1098     nothrow ubyte[] data()
1099     {
1100         ubyte[] result;
1101 
1102         foreach (ref chunk; chunks_)
1103             result ~= chunk.data[0..chunk.used];
1104 
1105         return result;
1106     }
1107 
1108 
1109     /**
1110      * Forwards to all buffer contents.
1111      *
1112      * Returns:
1113      *  the array of iovec struct that stores references.
1114      */
1115     @property @safe
1116     nothrow ref iovec[] vector()
1117     {
1118         return vecList_;
1119     }
1120 
1121 
1122     /**
1123      * Writes the argument to buffer and stores the reference of writed content
1124      * if the argument size is smaller than threshold,
1125      * otherwise stores the reference of argument directly.
1126      *
1127      * Params:
1128      *  value = the content to write.
1129      */
1130     @safe
1131     void put(in ubyte value)
1132     {
1133         ubyte[1] values = [value];
1134         putCopy(values);
1135     }
1136 
1137 
1138     /// ditto
1139     @safe
1140     void put(in ubyte[] value)
1141     {
1142         if (value.length < Threshold)
1143             putCopy(value);
1144         else
1145             putRef(value);
1146     }
1147 
1148 
1149   private:
1150     /*
1151      * Stores the reference of $(D_PARAM value).
1152      *
1153      * Params:
1154      *  value = the content to write.
1155      */
1156     @trusted
1157     void putRef(in ubyte[] value)
1158     {
1159         vecList_.length += 1;
1160         vecList_[$ - 1]  = iovec(cast(void*)value.ptr, value.length);
1161     }
1162 
1163 
1164     /*
1165      * Writes $(D_PARAM value) to buffer and appends to its reference.
1166      *
1167      * Params:
1168      *  value = the contents to write.
1169      */
1170     @trusted
1171     void putCopy(in ubyte[] value)
1172     {
1173         /*
1174          * Helper for expanding new space.
1175          */
1176         void expand(in size_t size)
1177         {
1178             const newSize = size < ChunkSize ? ChunkSize : size;
1179 
1180             index_++;
1181             chunks_.length = 1;
1182             chunks_[index_].data.length = newSize;
1183         }
1184 
1185         const size = value.length;
1186 
1187         // lacks current chunk?
1188         if (chunks_[index_].data.length - chunks_[index_].used < size)
1189             expand(size);
1190 
1191         const base = chunks_[index_].used;                     // start index
1192         auto  data = chunks_[index_].data[base..base + size];  // chunk to write
1193 
1194         data[] = value[];
1195         chunks_[index_].used += size;
1196 
1197         // Optimization for avoiding iovec allocation.
1198         if (vecList_.length && data.ptr == (vecList_[$ - 1].iov_base +
1199                                             vecList_[$ - 1].iov_len))
1200             vecList_[$ - 1].iov_len += size;
1201         else
1202             putRef(data);
1203     }
1204 }
1205 
1206 
1207 unittest
1208 {
1209     static assert(isOutputRange!(RefBuffer, ubyte) &&
1210                   isOutputRange!(RefBuffer, ubyte[]));
1211 
1212     auto buffer = RefBuffer(2, 4);
1213 
1214     ubyte[] tests = [1, 2];
1215     foreach (v; tests)
1216         buffer.put(v);
1217     buffer.put(tests);
1218 
1219     assert(buffer.data == tests, "putCopy failed");
1220 
1221     iovec[] vector = buffer.vector;
1222     ubyte[] result;
1223 
1224     assert(vector.length == 2, "Optimization failed");
1225 
1226     foreach (v; vector)
1227         result ~= (cast(ubyte*)v.iov_base)[0..v.iov_len];
1228 
1229     assert(result == tests ~ tests);
1230 }
1231 
1232 
1233 version (unittest)
1234 {
1235     mixin template DefinePacker()
1236     {
1237         Packer packer;
1238     }
1239 
1240     mixin template DefineDictionalPacker()
1241     {
1242         Packer packer = Packer(false);
1243     }
1244 }
1245 
1246 unittest
1247 {
1248     { // unique value
1249         mixin DefinePacker;
1250 
1251         ubyte[] result = [Format.NIL, Format.TRUE, Format.FALSE];
1252 
1253         packer.pack(null, true, false);
1254         foreach (i, value; packer.stream.data)
1255             assert(value == result[i]);
1256     }
1257     { // uint *
1258         static struct UTest { ubyte format; ulong value; }
1259 
1260         enum : ulong { A = ubyte.max, B = ushort.max, C = uint.max, D = ulong.max }
1261 
1262         static UTest[][] utests = [
1263             [{Format.UINT8, A}],
1264             [{Format.UINT8, A}, {Format.UINT16, B}],
1265             [{Format.UINT8, A}, {Format.UINT16, B}, {Format.UINT32, C}],
1266             [{Format.UINT8, A}, {Format.UINT16, B}, {Format.UINT32, C}, {Format.UINT64, D}],
1267         ];
1268 
1269         foreach (I, T; TypeTuple!(ubyte, ushort, uint, ulong)) {
1270             foreach (i, test; utests[I]) {
1271                 mixin DefinePacker;
1272 
1273                 packer.pack(cast(T)test.value);
1274                 assert(packer.stream.data[0] == test.format);
1275 
1276                 switch (i) {
1277                 case 0:
1278                     auto answer = take8from!(T.sizeof * 8)(test.value);
1279                     assert(memcmp(&packer.stream.data[1], &answer, ubyte.sizeof) == 0);
1280                     break;
1281                 case 1:
1282                     auto answer = convertEndianTo!16(test.value);
1283                     assert(memcmp(&packer.stream.data[1], &answer, ushort.sizeof) == 0);
1284                     break;
1285                 case 2:
1286                     auto answer = convertEndianTo!32(test.value);
1287                     assert(memcmp(&packer.stream.data[1], &answer, uint.sizeof) == 0);
1288                     break;
1289                 default:
1290                     auto answer = convertEndianTo!64(test.value);
1291                     assert(memcmp(&packer.stream.data[1], &answer, ulong.sizeof) == 0);
1292                 }
1293             }
1294         }
1295     }
1296     { // int *
1297         static struct STest { ubyte format; long value; }
1298 
1299         enum : long { A = byte.min, B = short.min, C = int.min, D = long.min }
1300 
1301         static STest[][] stests = [
1302             [{Format.INT8, A}],
1303             [{Format.INT8, A}, {Format.INT16, B}],
1304             [{Format.INT8, A}, {Format.INT16, B}, {Format.INT32, C}],
1305             [{Format.INT8, A}, {Format.INT16, B}, {Format.INT32, C}, {Format.INT64, D}],
1306         ];
1307 
1308         foreach (I, T; TypeTuple!(byte, short, int, long)) {
1309             foreach (i, test; stests[I]) {
1310                 mixin DefinePacker;
1311 
1312                 packer.pack(cast(T)test.value);
1313                 assert(packer.stream.data[0] == test.format);
1314 
1315                 switch (i) {
1316                 case 0:
1317                     auto answer = take8from!(T.sizeof * 8)(test.value);
1318                     assert(memcmp(&packer.stream.data[1], &answer, byte.sizeof) == 0);
1319                     break;
1320                 case 1:
1321                     auto answer = convertEndianTo!16(test.value);
1322                     assert(memcmp(&packer.stream.data[1], &answer, short.sizeof) == 0);
1323                     break;
1324                 case 2:
1325                     auto answer = convertEndianTo!32(test.value);
1326                     assert(memcmp(&packer.stream.data[1], &answer, int.sizeof) == 0);
1327                     break;
1328                 default:
1329                     auto answer = convertEndianTo!64(test.value);
1330                     assert(memcmp(&packer.stream.data[1], &answer, long.sizeof) == 0);
1331                 }
1332             }
1333         }
1334     }
1335     { // fload, double
1336         static if ((real.sizeof == double.sizeof) || !EnableReal)
1337         {
1338             alias TypeTuple!(float, double, double) FloatingTypes;
1339             static struct FTest { ubyte format; double value; }
1340 
1341             static FTest[] ftests = [
1342                 {Format.FLOAT,  float.min_normal},
1343                 {Format.DOUBLE, double.max},
1344                 {Format.DOUBLE, double.max},
1345             ];
1346         }
1347         else
1348         {
1349             alias TypeTuple!(float, double, real) FloatingTypes;
1350             static struct FTest { ubyte format; real value; }
1351 
1352             static FTest[] ftests = [
1353                 {Format.FLOAT,  float.min_normal},
1354                 {Format.DOUBLE, double.max},
1355                 {Format.REAL,   real.max},
1356             ];
1357         }
1358 
1359         foreach (I, T; FloatingTypes) {
1360             mixin DefinePacker;
1361 
1362             packer.pack(cast(T)ftests[I].value);
1363             assert(packer.stream.data[0] == ftests[I].format);
1364 
1365             switch (I) {
1366             case 0:
1367                 const answer = convertEndianTo!32(_f(cast(T)ftests[I].value).i);
1368                 assert(memcmp(&packer.stream.data[1], &answer, float.sizeof) == 0);
1369                 break;
1370             case 1:
1371                 const answer = convertEndianTo!64(_d(cast(T)ftests[I].value).i);
1372                 assert(memcmp(&packer.stream.data[1], &answer, double.sizeof) == 0);
1373                 break;
1374             default:
1375                 static if (EnableReal)
1376                 {
1377                     const t = _r(cast(T)ftests[I].value);
1378                     const f = convertEndianTo!64(t.fraction);
1379                     const e = convertEndianTo!16(t.exponent);
1380                     assert(memcmp(&packer.stream.data[1],            &f, f.sizeof) == 0);
1381                     assert(memcmp(&packer.stream.data[1 + f.sizeof], &e, e.sizeof) == 0);
1382                 }
1383                 else
1384                 {
1385                     const answer = convertEndianTo!64(_d(cast(T)ftests[I].value).i);
1386                     assert(memcmp(&packer.stream.data[1], &answer, double.sizeof) == 0);
1387                 }
1388             }
1389         }
1390     }
1391     { // pointer
1392         static struct PTest
1393         {
1394             ubyte format;
1395 
1396             union
1397             {
1398                 ulong*  p0;
1399                 long*   p1;
1400                 double* p2;
1401             }
1402         }
1403 
1404         PTest[] ptests = [PTest(Format.UINT64), PTest(Format.INT64), PTest(Format.DOUBLE)];
1405 
1406         ulong  v0 = ulong.max;
1407         long   v1 = long.min;
1408         double v2 = double.max;
1409 
1410         foreach (I, Index; TypeTuple!("0", "1", "2")) {
1411             mixin DefinePacker;
1412 
1413             mixin("ptests[I].p" ~ Index ~ " = &v" ~ Index ~ ";");
1414 
1415             packer.pack(mixin("ptests[I].p" ~ Index));
1416             assert(packer.stream.data[0] == ptests[I].format);
1417 
1418             switch (I) {
1419             case 0:
1420                 auto answer = convertEndianTo!64(*ptests[I].p0);
1421                 assert(memcmp(&packer.stream.data[1], &answer, ulong.sizeof) == 0);
1422                 break;
1423             case 1:
1424                 auto answer = convertEndianTo!64(*ptests[I].p1);
1425                 assert(memcmp(&packer.stream.data[1], &answer, long.sizeof) == 0);
1426                 break;
1427             default:
1428                 const answer = convertEndianTo!64(_d(*ptests[I].p2).i);
1429                 assert(memcmp(&packer.stream.data[1], &answer, double.sizeof) == 0);
1430             }
1431         }
1432     }
1433     { // enum
1434         enum E : ubyte { A = ubyte.max }
1435 
1436         mixin DefinePacker; E e = E.A;
1437 
1438         packer.pack(e);
1439         assert(packer.stream.data[0] == Format.UINT8);
1440 
1441         auto answer = E.A;
1442         assert(memcmp(&packer.stream.data[1], &answer, (OriginalType!E).sizeof) == 0);
1443     }
1444     { // container
1445         static struct CTest { ubyte format; size_t value; }
1446 
1447         enum : ulong { A = 16 / 2, B = ushort.max, C = uint.max }
1448 
1449         static CTest[][] ctests = [
1450             [{Format.ARRAY | A, Format.ARRAY | A}, {Format.ARRAY16, B}, {Format.ARRAY32, C}],
1451             [{Format.MAP   | A, Format.MAP   | A}, {Format.MAP16,   B}, {Format.MAP32,   C}],
1452         ];
1453 
1454         foreach (I, Name; TypeTuple!("Array", "Map")) {
1455             auto test = ctests[I];
1456 
1457             foreach (i, T; TypeTuple!(ubyte, ushort, uint)) {
1458                 mixin DefinePacker;
1459                 mixin("packer.begin" ~ Name ~ "(i ? test[i].value : A);");
1460 
1461                 assert(packer.stream.data[0] == test[i].format);
1462 
1463                 switch (i) {
1464                 case 0:
1465                     auto answer = take8from(test[i].value);
1466                     assert(memcmp(&packer.stream.data[0], &answer, ubyte.sizeof) == 0);
1467                     break;
1468                 case 1:
1469                     auto answer = convertEndianTo!16(test[i].value);
1470                     assert(memcmp(&packer.stream.data[1], &answer, ushort.sizeof) == 0);
1471                     break;
1472                 default:
1473                     auto answer = convertEndianTo!32(test[i].value);
1474                     assert(memcmp(&packer.stream.data[1], &answer, uint.sizeof) == 0);
1475                 }
1476             }
1477         }
1478     }
1479     { // user defined
1480         {
1481             static struct S
1482             {
1483                 uint num = uint.max;
1484 
1485                 void toMsgpack(P)(ref P p) const { p.packArray(num); }
1486             }
1487 
1488             mixin DefinePacker; S test;
1489 
1490             packer.pack(test);
1491 
1492             assert(packer.stream.data[0] == (Format.ARRAY | 1));
1493             assert(packer.stream.data[1] ==  Format.UINT32);
1494             assert(memcmp(&packer.stream.data[2], &test.num, uint.sizeof) == 0);
1495         }
1496         {
1497             mixin DefinePacker; auto test = tuple(true, false, uint.max);
1498 
1499             packer.pack(test);
1500 
1501             assert(packer.stream.data[0] == (Format.ARRAY | 3));
1502             assert(packer.stream.data[1] ==  Format.TRUE);
1503             assert(packer.stream.data[2] ==  Format.FALSE);
1504             assert(packer.stream.data[3] ==  Format.UINT32);
1505             assert(memcmp(&packer.stream.data[4], &test.field[2], uint.sizeof) == 0);
1506         }
1507         {
1508             static class C
1509             {
1510                 uint num;
1511 
1512                 this(uint n) { num = n; }
1513 
1514                 void toMsgpack(P)(ref P p) const { p.packArray(num); }
1515             }
1516 
1517             mixin DefinePacker; C test = new C(ushort.max);
1518 
1519             packer.pack(test);
1520 
1521             assert(packer.stream.data[0] == (Format.ARRAY | 1));
1522             assert(packer.stream.data[1] ==  Format.UINT16);
1523             assert(memcmp(&packer.stream.data[2], &test.num, ushort.sizeof) == 0);
1524         }
1525     }
1526     { // simple struct and class
1527         {
1528             static struct Simple
1529             {
1530                 uint num = uint.max;
1531             }
1532 
1533             static struct SimpleWithNonPacked1
1534             {
1535                 uint num = uint.max;
1536                 @nonPacked string str = "ignored";
1537             }
1538 
1539             static struct SimpleWithNonPacked2
1540             {
1541                 @nonPacked string str = "ignored";
1542                 uint num = uint.max;
1543             }
1544 
1545             static struct SimpleWithSkippedTypes
1546             {
1547                 int function(int) fn;
1548                 int delegate(int) dg;
1549                 uint num = uint.max;
1550             }
1551 
1552             foreach (Type; TypeTuple!(Simple, SimpleWithNonPacked1, SimpleWithNonPacked2, SimpleWithSkippedTypes)) {
1553                 mixin DefinePacker;
1554 
1555                 Type test;
1556                 packer.pack(test);
1557 
1558                 assert(packer.stream.data[0] == (Format.ARRAY | 1));
1559                 assert(packer.stream.data[1] ==  Format.UINT32);
1560                 assert(memcmp(&packer.stream.data[2], &test.num, uint.sizeof) == 0);
1561             }
1562         }
1563 
1564         static class SimpleA
1565         {
1566             bool flag = true;
1567         }
1568 
1569         static class SimpleB : SimpleA
1570         {
1571             ubyte type = 100;
1572         }
1573 
1574         static class SimpleC : SimpleB
1575         {
1576             uint num = uint.max;
1577         }
1578 
1579         static class SimpleCWithNonPacked1 : SimpleB
1580         {
1581             uint num = uint.max;
1582             @nonPacked string str = "ignored";
1583         }
1584 
1585         static class SimpleCWithNonPacked2 : SimpleB
1586         {
1587             @nonPacked string str = "ignored";
1588             uint num = uint.max;
1589         }
1590 
1591         static class SimpleCWithSkippedTypes : SimpleB
1592         {
1593             uint num = uint.max;
1594             int function(int) fn;
1595             int delegate(int) dg;
1596         }
1597 
1598         {  // from derived class
1599             foreach (Type; TypeTuple!(SimpleC, SimpleCWithNonPacked1, SimpleCWithNonPacked2, SimpleCWithSkippedTypes)) {
1600                 mixin DefinePacker;
1601 
1602                 Type test = new Type();
1603                 packer.pack(test);
1604 
1605                 assert(packer.stream.data[0] == (Format.ARRAY | 3));
1606                 assert(packer.stream.data[1] ==  Format.TRUE);
1607                 assert(packer.stream.data[2] ==  100);
1608                 assert(packer.stream.data[3] ==  Format.UINT32);
1609                 assert(memcmp(&packer.stream.data[4], &test.num, uint.sizeof) == 0);
1610             }
1611         }
1612         {  // from base class
1613             mixin DefinePacker; SimpleB test = new SimpleC();
1614 
1615             try {
1616                 packer.pack(test);
1617                 assert(false);
1618             } catch (Exception e) { }
1619         }
1620     }
1621 }
1622 
1623 
1624 // deserializing routines
1625 
1626 
1627 /**
1628  * $(D UnpackException) is thrown on deserialization failure
1629  */
1630 class UnpackException : MessagePackException
1631 {
1632     this(string message)
1633     {
1634         super(message);
1635     }
1636 }
1637 
1638 
1639 version (D_Ddoc)
1640 {
1641     /**
1642      * Internal buffer and related operations for Unpacker
1643      *
1644      * Following Unpackers mixin this template. So, Unpacker can use following methods.
1645      *
1646      * -----
1647      * //buffer image:
1648      * +-------------------------------------------+
1649      * | [object] | [obj | unparsed... | unused... |
1650      * +-------------------------------------------+
1651      *            ^ offset
1652      *                   ^ current
1653      *                                 ^ used
1654      *                                             ^ buffer.length
1655      * -----
1656      *
1657      * This mixin template is a private.
1658      */
1659     mixin template InternalBuffer()
1660     {
1661       private:
1662         ubyte[] buffer_;  // internal buffer
1663         size_t  used_;    // index that buffer cosumed
1664         size_t  offset_;  // index that buffer parsed
1665         size_t  parsed_;  // total size of parsed message
1666         bool    hasRaw_;  // indicates whether Raw object has been deserialized
1667 
1668 
1669       public:
1670         /**
1671          * Forwards to internal buffer.
1672          *
1673          * Returns:
1674          *  the reference of internal buffer.
1675          */
1676         @property @safe
1677         nothrow ubyte[] buffer();
1678 
1679 
1680         /**
1681          * Fills internal buffer with $(D_PARAM target).
1682          *
1683          * Params:
1684          *  target = new serialized buffer to deserialize.
1685          */
1686         @safe void feed(in ubyte[] target);
1687 
1688 
1689         /**
1690          * Consumes buffer. This method is helper for buffer property.
1691          * You must use this method if you write bytes to buffer directly.
1692          *
1693          * Params:
1694          *  size = the number of consuming.
1695          */
1696         @safe
1697         nothrow void bufferConsumed(in size_t size);
1698 
1699 
1700         /**
1701          * Removes unparsed buffer.
1702          */
1703         @safe
1704         nothrow void removeUnparsed();
1705 
1706 
1707         /**
1708          * Returns:
1709          *  the total size including unparsed buffer size.
1710          */
1711         @property @safe
1712         nothrow size_t size() const;
1713 
1714 
1715         /**
1716          * Returns:
1717          *  the parsed size of buffer.
1718          */
1719         @property @safe
1720         nothrow size_t parsedSize() const;
1721 
1722 
1723         /**
1724          * Returns:
1725          *  the unparsed size of buffer.
1726          */
1727         @property @safe
1728         nothrow size_t unparsedSize() const;
1729 
1730 
1731     private:
1732         @safe
1733         void initializeBuffer(in ubyte[] target, in size_t bufferSize = 8192);
1734     }
1735 }
1736 else
1737 {
1738     private mixin template InternalBuffer()
1739     {
1740       private:
1741         ubyte[] buffer_;  // internal buffer
1742         size_t  used_;    // index that buffer cosumed
1743         size_t  offset_;  // index that buffer parsed
1744         size_t  parsed_;  // total size of parsed message
1745         bool    hasRaw_;  // indicates whether Raw object has been deserialized
1746 
1747 
1748       public:
1749         @property @safe
1750         nothrow ubyte[] buffer()
1751         {
1752             return buffer_;
1753         }
1754 
1755 
1756         @safe
1757         void feed(in ubyte[] target)
1758         in
1759         {
1760             assert(target.length);
1761         }
1762         body
1763         {
1764             /*
1765              * Expands internal buffer.
1766              *
1767              * Params:
1768              *  size = new buffer size to append.
1769              */
1770             void expandBuffer(in size_t size)
1771             {
1772                 // rewinds buffer(completed deserialization)
1773                 if (used_ == offset_ && !hasRaw_) {
1774                     used_ =  offset_ = 0;
1775 
1776                     if (buffer_.length < size)
1777                         buffer_.length = size;
1778 
1779                     return;
1780                 }
1781 
1782                 // deserializing state is mid-flow(buffer has non-parsed data yet)
1783                 auto unparsed = buffer_[offset_..used_];
1784                 auto restSize = buffer_.length - used_ + offset_;
1785                 auto newSize  = size > restSize ? unparsedSize + size : buffer_.length;
1786 
1787                 if (hasRaw_) {
1788                     hasRaw_ = false;
1789                     buffer_ = new ubyte[](newSize);
1790                 } else {
1791                     buffer_.length = newSize;
1792 
1793                     // avoids overlapping copy
1794                     auto area = buffer_[0..unparsedSize];
1795                     unparsed  = area.overlap(unparsed) ? unparsed.dup : unparsed;
1796                 }
1797 
1798                 buffer_[0..unparsedSize] = unparsed[];
1799                 used_   = unparsedSize;
1800                 offset_ = 0;
1801             }
1802 
1803             const size = target.length;
1804 
1805             // lacks current buffer?
1806             if (buffer_.length - used_ < size)
1807                 expandBuffer(size);
1808 
1809             buffer_[used_..used_ + size] = target[];
1810             used_ += size;
1811         }
1812 
1813 
1814         @safe
1815         nothrow void bufferConsumed(in size_t size)
1816         {
1817             if (used_ + size > buffer_.length)
1818                 used_ = buffer_.length;
1819             else
1820                 used_ += size;
1821         }
1822 
1823 
1824         @safe
1825         nothrow void removeUnparsed()
1826         {
1827             used_ = offset_;
1828         }
1829 
1830 
1831         @property @safe
1832         nothrow size_t size() const
1833         {
1834             return parsed_ - offset_ + used_;
1835         }
1836 
1837 
1838         @property @safe
1839         nothrow size_t parsedSize() const
1840         {
1841             return parsed_;
1842         }
1843 
1844 
1845         @property @safe
1846         nothrow size_t unparsedSize() const
1847         {
1848             return used_ - offset_;
1849         }
1850 
1851 
1852       private:
1853         @safe
1854         nothrow void initializeBuffer(in ubyte[] target, in size_t bufferSize = 8192)
1855         {
1856             const size = target.length;
1857 
1858             buffer_ = new ubyte[](size > bufferSize ? size : bufferSize);
1859             used_   = size;
1860             buffer_[0..size] = target[];
1861         }
1862     }
1863 }
1864 
1865 
1866 /**
1867  * This $(D Unpacker) is a $(D MessagePack) direct-conversion deserializer
1868  *
1869  * This implementation is suitable for fixed data.
1870  *
1871  * Example:
1872  * -----
1873  * // serializedData is [10, 0.1, false]
1874  * auto unpacker = Unpacker(serializedData);
1875  *
1876  * uint   n;
1877  * double d;
1878  * bool   b;
1879  *
1880  * unpacker.unpackArray(n, d, b);
1881  *
1882  * // using Tuple
1883  * Tuple!(uint, double, bool) record;
1884  * unpacker.unpack(record);  // record is [10, 0.1, false]
1885  * -----
1886  *
1887  * NOTE:
1888  *  Unpacker becomes template struct if Phobos supports truly IO module.
1889  */
1890 struct Unpacker
1891 {
1892   private:
1893     static @system
1894     {
1895         alias void delegate(ref Unpacker, void*) UnpackHandler;
1896         UnpackHandler[TypeInfo] unpackHandlers;
1897 
1898         public void registerHandler(T, alias Handler)()
1899         {
1900             unpackHandlers[typeid(T)] = delegate(ref Unpacker unpacker, void* obj) {
1901                 Handler(unpacker, *cast(T*)obj);
1902             };
1903         }
1904     }
1905 
1906     enum Offset = 1;
1907 
1908     mixin InternalBuffer;
1909 
1910     bool withFieldName_;
1911 
1912 
1913   public:
1914     /**
1915      * Constructs a $(D Unpacker).
1916      *
1917      * Params:
1918      *  target     = byte buffer to deserialize
1919      *  bufferSize = size limit of buffer size
1920      */
1921     this(in ubyte[] target, in size_t bufferSize = 8192, bool withFieldName = false)
1922     {
1923         initializeBuffer(target, bufferSize);
1924         withFieldName_ = withFieldName;
1925     }
1926 
1927 
1928     /**
1929      * Clears states for next deserialization.
1930      */
1931     @safe
1932     nothrow void clear()
1933     {
1934         parsed_ = 0;
1935     }
1936 
1937 
1938     /**
1939      * Deserializes $(D_PARAM T) object and assigns to $(D_PARAM value).
1940      *
1941      * If the argument is pointer, dereferences pointer and assigns deserialized value.
1942      * -----
1943      * int* a;
1944      * unpacker.unpack(a)  // enforce throws Exception because a is null or
1945      *                     // no throw if deserialized value is nil
1946      *
1947      * int b; a = &b;
1948      * unpacker.unpack(b)  // b is deserialized value or
1949      *                     // assigns null if deserialized value is nil
1950      * -----
1951      *
1952      * Params:
1953      *  value = the reference of value to assign.
1954      *
1955      * Returns:
1956      *  self, i.e. for method chaining.
1957      *
1958      * Throws:
1959      *  UnpackException when doesn't read from buffer or precision loss occurs and
1960      *  MessagePackException when $(D_PARAM T) type doesn't match serialized type.
1961      */
1962     ref Unpacker unpack(T)(ref T value) if (is(Unqual!T == bool))
1963     {
1964         canRead(Offset, 0);
1965         const header = read();
1966 
1967         switch (header) {
1968         case Format.TRUE:
1969             value = true;
1970             break;
1971         case Format.FALSE:
1972             value = false;
1973             break;
1974         default:
1975             rollback();
1976         }
1977 
1978         return this;
1979     }
1980 
1981 
1982     /// ditto
1983     ref Unpacker unpack(T)(ref T value) if (isUnsigned!T && !is(Unqual!T == enum))
1984     {
1985         canRead(Offset, 0);
1986         const header = read();
1987 
1988         if (0x00 <= header && header <= 0x7f) {
1989             value = header;
1990         } else {
1991             switch (header) {
1992             case Format.UINT8:
1993                 canRead(ubyte.sizeof);
1994                 value = read();
1995                 break;
1996             case Format.UINT16:
1997                 canRead(ushort.sizeof);
1998                 auto us = load16To!ushort(read(ushort.sizeof));
1999                 if (us > T.max)
2000                     rollback(ushort.sizeof);
2001                 value = cast(T)us;
2002                 break;
2003             case Format.UINT32:
2004                 canRead(uint.sizeof);
2005                 auto ui = load32To!uint(read(uint.sizeof));
2006                 if (ui > T.max)
2007                     rollback(uint.sizeof);
2008                 value = cast(T)ui;
2009                 break;
2010             case Format.UINT64:
2011                 canRead(ulong.sizeof);
2012                 auto ul = load64To!ulong(read(ulong.sizeof));
2013                 if (ul > T.max)
2014                     rollback(ulong.sizeof);
2015                 value = cast(T)ul;
2016                 break;
2017             default:
2018                 rollback();
2019             }
2020         }
2021 
2022         return this;
2023     }
2024 
2025 
2026     /// ditto
2027     ref Unpacker unpack(T)(ref T value) if (isSigned!T && isIntegral!T && !is(Unqual!T == enum))
2028     {
2029         canRead(Offset, 0);
2030         const header = read();
2031 
2032         if (0x00 <= header && header <= 0x7f) {
2033             value = cast(T)header;
2034         } else if (0xe0 <= header && header <= 0xff) {
2035             value = -(cast(T)-header);
2036         } else {
2037             switch (header) {
2038             case Format.UINT8:
2039                 canRead(ubyte.sizeof);
2040                 auto ub = read();
2041                 if (ub > T.max)
2042                     rollback(ubyte.sizeof);
2043                 value = cast(T)ub;
2044                 break;
2045             case Format.UINT16:
2046                 canRead(ushort.sizeof);
2047                 auto us = load16To!ushort(read(ushort.sizeof));
2048                 if (us > T.max)
2049                     rollback(ushort.sizeof);
2050                 value = cast(T)us;
2051                 break;
2052             case Format.UINT32:
2053                 canRead(uint.sizeof);
2054                 auto ui = load32To!uint(read(uint.sizeof));
2055                 if (ui > T.max)
2056                     rollback(uint.sizeof);
2057                 value = cast(T)ui;
2058                 break;
2059             case Format.UINT64:
2060                 canRead(ulong.sizeof);
2061                 auto ul = load64To!ulong(read(ulong.sizeof));
2062                 if (ul > T.max)
2063                     rollback(ulong.sizeof);
2064                 value = cast(T)ul;
2065                 break;
2066             case Format.INT8:
2067                 canRead(byte.sizeof);
2068                 value = cast(byte)read();
2069                 break;
2070             case Format.INT16:
2071                 canRead(short.sizeof);
2072                 auto s = load16To!short(read(short.sizeof));
2073                 if (s < T.min || T.max < s)
2074                     rollback(short.sizeof);
2075                 value = cast(T)s;
2076                 break;
2077             case Format.INT32:
2078                 canRead(int.sizeof);
2079                 auto i = load32To!int(read(int.sizeof));
2080                 if (i < T.min || T.max < i)
2081                     rollback(int.sizeof);
2082                 value = cast(T)i;
2083                 break;
2084             case Format.INT64:
2085                 canRead(long.sizeof);
2086                 auto l = load64To!long(read(long.sizeof));
2087                 if (l < T.min || T.max < l)
2088                     rollback(long.sizeof);
2089                 value = cast(T)l;
2090                 break;
2091             default:
2092                 rollback();
2093             }
2094         }
2095 
2096         return this;
2097     }
2098 
2099 
2100     /// ditto
2101     ref Unpacker unpack(T)(ref T value) if (isFloatingPoint!T && !is(Unqual!T == enum))
2102     {
2103         canRead(Offset, 0);
2104         const header = read();
2105 
2106         switch (header) {
2107         case Format.FLOAT:
2108             _f temp;
2109 
2110             canRead(uint.sizeof);
2111             temp.i = load32To!uint(read(uint.sizeof));
2112             value  = temp.f;
2113             break;
2114         case Format.DOUBLE:
2115             // check precision loss
2116             static if (is(Unqual!T == float))
2117                 rollback();
2118 
2119             _d temp;
2120 
2121             canRead(ulong.sizeof);
2122             temp.i = load64To!ulong(read(ulong.sizeof));
2123             value  = temp.f;
2124             break;
2125         case Format.REAL:
2126             static if (!EnableReal)
2127             {
2128                 rollback();
2129             }
2130             else
2131             {
2132                 // check precision loss
2133                 static if (is(Unqual!T == float) || is(Unqual!T == double))
2134                     rollback();
2135 
2136                 canRead(RealSize);
2137 
2138                 version (NonX86)
2139                 {
2140                     CustomFloat!80 temp;
2141 
2142                     const frac = load64To!ulong (read(ulong.sizeof));
2143                     const exp  = load16To!ushort(read(ushort.sizeof));
2144 
2145                     temp.significand = frac;
2146                     temp.exponent    = exp & 0x7fff;
2147                     temp.sign        = exp & 0x8000 ? true : false;
2148 
2149                     // NOTE: temp.get!real is inf on non-x86 when deserialized value is larger than double.max.
2150                     value = temp.get!real;
2151                 }
2152                 else
2153                 {
2154                     _r temp;
2155 
2156                     temp.fraction = load64To!(typeof(temp.fraction))(read(temp.fraction.sizeof));
2157                     temp.exponent = load16To!(typeof(temp.exponent))(read(temp.exponent.sizeof));
2158 
2159                     value = temp.f;
2160                 }
2161             }
2162 
2163             break;
2164         default:
2165             rollback();
2166         }
2167 
2168         return this;
2169     }
2170 
2171 
2172     /// ditto
2173     ref Unpacker unpack(T)(ref T value) if (is(Unqual!T == enum))
2174     {
2175         OriginalType!T temp;
2176 
2177         unpack(temp);
2178 
2179         value = cast(T)temp;
2180 
2181         return this;
2182     }
2183 
2184 
2185     /// ditto
2186     ref Unpacker unpack(T)(T value) if (isPointer!T)
2187     {
2188         static if (is(Unqual!T == void*)) {
2189             enforce(value !is null,  "Can't deserialize void type");
2190             unpackNil(value);
2191         } else {
2192             if (checkNil())
2193                 unpackNil(value);
2194             else
2195                 enforce(value !is null, T.stringof ~ " is null pointer");
2196 
2197             unpack(mixin(AsteriskOf!T ~ "value"));
2198         }
2199 
2200         return this;
2201     }
2202 
2203 
2204     /// ditto
2205     ref Unpacker unpack(Types...)(ref Types objects) if (Types.length > 1)
2206     {
2207         foreach (i, T; Types)
2208             unpack!(T)(objects[i]);
2209 
2210         return this;
2211     }
2212 
2213 
2214     /**
2215      * Deserializes $(D_PARAM T) object and assigns to $(D_PARAM array).
2216      *
2217      * This is convenient method for array deserialization.
2218      * Rollback will be completely successful if you deserialize raw type((u)byte[] or string types).
2219      * But, Rollback will be one element(e.g. int) if you deserialize other types(e.g. int[], int[int])
2220      *
2221      * No assign if the length of deserialized object is 0.
2222      *
2223      * In a static array, this method checks the length. Do rollback and throw exception
2224      * if length of $(D_PARAM array) is different from length of deserialized object.
2225      *
2226      * Params:
2227      *  array = the reference of array to assign.
2228      *
2229      * Returns:
2230      *  self, i.e. for method chaining.
2231      *
2232      * Throws:
2233      *  UnpackException when doesn't read from buffer or precision loss occurs and
2234      *  MessagePackException when $(D_PARAM T) type doesn't match serialized type.
2235      */
2236     ref Unpacker unpack(T)(ref T array) if (isArray!T && !is(Unqual!T == enum))
2237     {
2238         alias typeof(T.init[0]) U;
2239 
2240         /*
2241          * Deserializes type-information of raw type.
2242          */
2243         @safe
2244         size_t beginRaw()
2245         {
2246             canRead(Offset, 0);
2247             const  header = read();
2248             size_t length;
2249 
2250             if (0xa0 <= header && header <= 0xbf) {
2251                 length = header & 0x1f;
2252             } else {
2253                 switch (header) {
2254                 case Format.BIN8, Format.STR8:
2255                     canRead(ubyte.sizeof);
2256                     length = read();
2257                     break;
2258                 case Format.BIN16, Format.RAW16:
2259                     canRead(ushort.sizeof);
2260                     length = load16To!size_t(read(ushort.sizeof));
2261                     break;
2262                 case Format.BIN32, Format.RAW32:
2263                     canRead(uint.sizeof);
2264                     length = load32To!size_t(read(uint.sizeof));
2265                     break;
2266                 case Format.NIL:
2267                     break;
2268                 default:
2269                     rollback();
2270                 }
2271             }
2272 
2273             return length;
2274         }
2275 
2276 
2277         if (checkNil()) {
2278             static if (isStaticArray!T) {
2279                 onInvalidType();
2280             } else {
2281                 return unpackNil(array);
2282             }
2283         }
2284 
2285         // Raw bytes
2286         static if (isByte!U || isSomeChar!U) {
2287             auto length = beginRaw();
2288             auto offset = calculateSize!(true)(length);
2289             if (length == 0)
2290                 return this;
2291 
2292             static if (isStaticArray!T) {
2293                 if (length != array.length)
2294                     rollback(offset);
2295             }
2296 
2297             canRead(length, offset + Offset);
2298             static if (isStaticArray!T) {
2299                 array[] = (cast(U[])read(length))[0 .. T.length];
2300             } else {
2301                 array = cast(T)read(length);
2302             }
2303 
2304             static if (isDynamicArray!T)
2305                 hasRaw_ = true;
2306         } else {
2307             auto length = beginArray();
2308             if (length == 0)
2309                 return this;
2310 
2311             static if (isStaticArray!T) {
2312                 if (length != array.length)
2313                     rollback(calculateSize(length));
2314             } else {
2315                 array.length = length;
2316             }
2317 
2318             foreach (i; 0..length)
2319                 unpack(array[i]);
2320         }
2321 
2322         return this;
2323     }
2324 
2325 
2326     /// ditto
2327     ref Unpacker unpack(T)(ref T array) if (isAssociativeArray!T)
2328     {
2329         alias typeof(T.init.keys[0])   K;
2330         alias typeof(T.init.values[0]) V;
2331 
2332         if (checkNil())
2333             return unpackNil(array);
2334 
2335         auto length = beginMap();
2336         if (length == 0)
2337             return this;
2338 
2339         foreach (i; 0..length) {
2340             K k; unpack(k);
2341             V v; unpack(v);
2342             array[k] = v;
2343         }
2344 
2345         return this;
2346     }
2347 
2348 
2349     /**
2350      * Deserializes $(D_PARAM T) object and assigns to $(D_PARAM object).
2351      *
2352      * Calling $(D fromMsgpack) if $(D_KEYWORD class) and $(D_KEYWORD struct) implement $(D fromMsgpack) method. $(D fromMsgpack) signature is:
2353      * -----
2354      * void fromMsgpack(ref Unpacker unpacker)
2355      * -----
2356      * Assumes $(D std.typecons.Tuple) or simple struct if $(D_KEYWORD struct) doesn't implement $(D fromMsgpack).
2357      * Checks length if $(D_PARAM T) is a $(D std.typecons.Tuple) or simple struct.
2358      *
2359      * Params:
2360      *  object = the reference of object to assign.
2361      *  args   = the arguments to class constructor(class only).
2362      *           This is used at new statement if $(D_PARAM object) is $(D_KEYWORD null).
2363      *
2364      * Returns:
2365      *  self, i.e. for method chaining.
2366      */
2367     ref Unpacker unpack(T, Args...)(ref T object, auto ref Args args) if (is(Unqual!T == class))
2368     {
2369         if (checkNil())
2370             return unpackNil(object);
2371 
2372         if (object is null) {
2373             //static if (is(typeof(new T(args))))
2374             static if (__traits(compiles, { new T(args); }))
2375                 object = new T(args);
2376             else
2377                 throw new MessagePackException("Don't know how to construct class type '" ~ Unqual!T.stringof ~ "' with argument types '" ~ Args.stringof ~ "'.");
2378         }
2379 
2380         static if (hasMember!(T, "fromMsgpack"))
2381         {
2382             static if (__traits(compiles, { T t; t.fromMsgpack(this, withFieldName_); })) {
2383               object.fromMsgpack(this, withFieldName_);
2384             } else static if (__traits(compiles, { T t; t.fromMsgpack(this); })) { // backward compatible
2385                 object.fromMsgpack(this);
2386             } else {
2387                 static assert(0, "Failed to invoke 'fromMsgpack' on type '" ~ Unqual!T.stringof ~ "'");
2388             }
2389         } else {
2390             if (auto handler = object.classinfo in unpackHandlers) {
2391                 (*handler)(this, cast(void*)&object);
2392                 return this;
2393             }
2394             if (T.classinfo !is object.classinfo) {
2395                 throw new MessagePackException("Can't unpack derived class through reference to base class.");
2396             }
2397 
2398             alias SerializingClasses!(T) Classes;
2399 
2400             size_t length = withFieldName_ ? beginMap() : beginArray();
2401             if (length == 0)
2402                 return this;
2403 
2404             if (length != SerializingMemberNumbers!(Classes))
2405                 rollback(calculateSize(length));
2406 
2407             if (withFieldName_) {
2408                 foreach (_; 0..length) {
2409                     string fieldName;
2410                     unpack(fieldName);
2411 
2412                     foreach (Class; Classes) {
2413                         Class obj = cast(Class)object;
2414 
2415                         foreach (i, member; obj.tupleof) {
2416                             static if (isPackedField!(Class.tupleof[i]))
2417                             {
2418                                 if (fieldName == getFieldName!(Class, i)) {
2419                                     unpack(obj.tupleof[i]);
2420                                     goto endLoop;
2421                                 }
2422                             }
2423                         }
2424                     }
2425                     assert(false, "Invalid field name: '" ~ fieldName~"' ");
2426 
2427                 endLoop:
2428                     continue;
2429                 }
2430             } else {
2431                 foreach (Class; Classes) {
2432                     Class obj = cast(Class)object;
2433 
2434                     foreach (i, member; obj.tupleof) {
2435                         static if (isPackedField!(Class.tupleof[i]))
2436                             unpack(obj.tupleof[i]);
2437                     }
2438                 }
2439             }
2440         }
2441 
2442         return this;
2443     }
2444 
2445 
2446     /// ditto
2447     ref Unpacker unpack(T)(ref T object) if (is(Unqual!T == struct))
2448     {
2449         static if (hasMember!(T, "fromMsgpack"))
2450         {
2451             static if (__traits(compiles, { T t; t.fromMsgpack(this); })) {
2452                 object.fromMsgpack(this);
2453             } else {
2454                 static assert(0, "Failed to invoke 'fromMsgpack' on type '" ~ Unqual!T.stringof ~ "'");
2455             }
2456         } else {
2457             if (auto handler = typeid(T) in unpackHandlers) {
2458                 (*handler)(this, cast(void*)&object);
2459                 return this;
2460             }
2461 
2462             auto length = beginArray();
2463             if (length == 0)
2464                 return this;
2465 
2466             static if (isTuple!T) {
2467                 if (length != T.Types.length)
2468                     rollback(calculateSize(length));
2469 
2470                 foreach (i, Type; T.Types)
2471                     unpack(object.field[i]);
2472             } else {  // simple struct
2473                 //if (length != object.tupleof.length)
2474                 if (length != SerializingMemberNumbers!(T))
2475                     rollback(calculateSize(length));
2476 
2477                 foreach (i, member; object.tupleof) {
2478                     static if (isPackedField!(T.tupleof[i]))
2479                         unpack(object.tupleof[i]);
2480                 }
2481             }
2482         }
2483 
2484         return this;
2485     }
2486 
2487 
2488     /**
2489      * Deserializes the container object and assigns to each argument.
2490      *
2491      * These methods check the length. Do rollback if
2492      * the length of arguments is different from length of deserialized object.
2493      *
2494      * In unpackMap, the number of arguments must be even.
2495      *
2496      * Params:
2497      *  objects = the references of object to assign.
2498      *
2499      * Returns:
2500      *  self, i.e. for method chaining.
2501      */
2502     ref Unpacker unpackArray(Types...)(ref Types objects)
2503     {
2504         auto length = beginArray();
2505         if (length != Types.length)
2506             rollback(calculateSize(length));
2507 
2508         foreach (i, T; Types)
2509             unpack(objects[i]);
2510         // unpack(objects);  // slow :(
2511 
2512         return this;
2513     }
2514 
2515 
2516     /// ditto
2517     ref Unpacker unpackMap(Types...)(ref Types objects)
2518     {
2519         static assert(Types.length % 2 == 0, "The number of arguments must be even");
2520 
2521         auto length = beginMap();
2522         if (length != Types.length / 2)
2523             rollback(calculateSize(length));
2524 
2525         foreach (i, T; Types)
2526             unpack(objects[i]);
2527 
2528         return this;
2529     }
2530 
2531 
2532     /**
2533      * Deserializes the type-information of container.
2534      *
2535      * These methods don't deserialize contents.
2536      * You need to call unpack method to deserialize contents at your own risk.
2537      * -----
2538      * // serialized data is [1, "Hi!"];
2539      * int num;
2540      * unpacker.beginArray(2).unpack(num);  // num is 1
2541      *
2542      * // other operation
2543      *
2544      * string str;
2545      * unpacker.unpack(str);  // str is "Hi!"
2546      * -----
2547      *
2548      * Returns:
2549      *  the container size.
2550      */
2551     @safe
2552     size_t beginArray()
2553     {
2554         canRead(Offset, 0);
2555         const  header = read();
2556         size_t length;
2557 
2558         if (0x90 <= header && header <= 0x9f) {
2559             length = header & 0x0f;
2560         } else {
2561             switch (header) {
2562             case Format.ARRAY16:
2563                 canRead(ushort.sizeof);
2564                 length = load16To!size_t(read(ushort.sizeof));
2565                 break;
2566             case Format.ARRAY32:
2567                 canRead(uint.sizeof);
2568                 length = load32To!size_t(read(uint.sizeof));
2569                 break;
2570             case Format.NIL:
2571                 break;
2572             default:
2573                 rollback();
2574             }
2575         }
2576 
2577         return length;
2578     }
2579 
2580 
2581     /// ditto
2582     @safe
2583     size_t beginMap()
2584     {
2585         canRead(Offset, 0);
2586         const  header = read();
2587         size_t length;
2588 
2589         if (0x80 <= header && header <= 0x8f) {
2590             length = header & 0x0f;
2591         } else {
2592             switch (header) {
2593             case Format.MAP16:
2594                 canRead(ushort.sizeof);
2595                 length = load16To!size_t(read(ushort.sizeof));
2596                 break;
2597             case Format.MAP32:
2598                 canRead(uint.sizeof);
2599                 length = load32To!size_t(read(uint.sizeof));
2600                 break;
2601             case Format.NIL:
2602                 break;
2603             default:
2604                 rollback();
2605             }
2606         }
2607 
2608         return length;
2609     }
2610 
2611 
2612     /**
2613      * Scans an entire buffer and converts each objects.
2614      *
2615      * This method is used for unpacking record-like objects.
2616      *
2617      * Example:
2618      * -----
2619      * // serialized data is "[1, 2][3, 4][5, 6][...".
2620      * auto unpacker = Unpacker(serializedData);
2621      * foreach (n, d; &unpacker.scan!(int, int))  // == "foreach (int n, int d; unpacker)"
2622      *     writeln(n, d); // 1st loop "1, 2", 2nd loop "3, 4"...
2623      * -----
2624      */
2625     int scan(Types...)(scope int delegate(ref Types) dg)
2626     {
2627         return opApply!(Types)(delegate int(ref Types objects) { return dg(objects); });
2628     }
2629 
2630 
2631     /// ditto
2632     int opApply(Types...)(scope int delegate(ref Types) dg)
2633     {
2634         int result;
2635 
2636         while (used_ - offset_) {
2637             auto length = beginArray();
2638             if (length != Types.length)
2639                 rollback(calculateSize(length));
2640 
2641             Types objects;
2642             foreach (i, T; Types)
2643                 unpack(objects[i]);
2644 
2645             result = dg(objects);
2646             if (result)
2647                 return result;
2648         }
2649 
2650         return result;
2651     }
2652 
2653 
2654   private:
2655     /*
2656      * Deserializes nil object and assigns to $(D_PARAM value).
2657      *
2658      * Params:
2659      *  value = the reference of value to assign.
2660      *
2661      * Returns:
2662      *  self, i.e. for method chaining.
2663      *
2664      * Throws:
2665      *  UnpackException when doesn't read from buffer or precision loss occurs and
2666      *  MessagePackException when $(D_PARAM T) type doesn't match serialized type.
2667      */
2668     @safe
2669     ref Unpacker unpackNil(T)(ref T value)
2670     {
2671         canRead(Offset, 0);
2672         const header = read();
2673 
2674         if (header == Format.NIL)
2675             value = null;
2676         else
2677             rollback();
2678 
2679         return this;
2680     }
2681 
2682 
2683     /*
2684      * Next object is nil?
2685      *
2686      * Returns:
2687      *  true if next object is nil.
2688      */
2689     @safe
2690     bool checkNil()
2691     {
2692         canRead(Offset, 0);
2693 
2694         return buffer_[offset_] == Format.NIL;
2695     }
2696 
2697 
2698     /*
2699      * Calculates the format size of container length.
2700      */
2701     size_t calculateSize(bool rawType = false)(in size_t length)
2702     {
2703         static if (rawType)
2704             return length < 32 ? 0 : length < 65536 ? ushort.sizeof : uint.sizeof;
2705         else
2706             return length < 16 ? 0 : length < 65536 ? ushort.sizeof : uint.sizeof;
2707     }
2708 
2709 
2710     /*
2711      * Reading test.
2712      *
2713      * Params:
2714      *  size   = the size to read.
2715      *  offset = the offset to subtract when doesn't read from buffer.
2716      *
2717      * Throws:
2718      *  UnpackException when doesn't read from buffer.
2719      */
2720     @safe
2721     void canRead(in size_t size, in size_t offset = Offset)
2722     {
2723         if (used_ - offset_ < size) {
2724             if (offset)
2725                 offset_ -= offset;
2726 
2727             throw new UnpackException("Insufficient buffer");
2728         }
2729     }
2730 
2731 
2732     /*
2733      * Reads value from buffer and advances offset.
2734      */
2735     @safe
2736     nothrow ubyte read()
2737     {
2738         return buffer_[offset_++];
2739     }
2740 
2741 
2742     /*
2743      * Reads value from buffer and advances offset.
2744      */
2745     @safe
2746     nothrow ubyte[] read(in size_t size)
2747     {
2748         auto result = buffer_[offset_..offset_ + size];
2749 
2750         offset_ += size;
2751 
2752         return result;
2753     }
2754 
2755 
2756     /*
2757      * Do rollback and throws exception.
2758      */
2759     @safe
2760     void rollback(in size_t size = 0)
2761     {
2762         offset_ -= size + Offset;
2763         onInvalidType();
2764     }
2765 }
2766 
2767 
2768 /**
2769  * Register a deserialization handler for $(D_PARAM T) type
2770  *
2771  * Example:
2772  * -----
2773  * registerUnackHandler!(Foo, fooUnackHandler);
2774  * -----
2775  */
2776 void registerUnpackHandler(T, alias Handler)()
2777 {
2778     Unpacker.registerHandler!(T, Handler);
2779 }
2780 
2781 
2782 unittest
2783 {
2784     { // unique
2785         mixin DefinePacker;
2786 
2787         Tuple!(bool, bool) result;
2788         Tuple!(bool, bool) test = tuple(true, false);
2789 
2790         packer.pack(test);
2791 
2792         auto unpacker = Unpacker(packer.stream.data);
2793 
2794         unpacker.unpack(result);
2795         assert(test == result);
2796     }
2797     { // uint *
2798         mixin DefinePacker;
2799 
2800         Tuple!(ubyte, ushort, uint, ulong) result;
2801         Tuple!(ubyte, ushort, uint, ulong) test = tuple(cast(ubyte)ubyte.max, cast(ushort)ushort.max,
2802                                                         cast(uint)uint.max,   cast(ulong)ulong.max);
2803 
2804         packer.pack(test);
2805 
2806         auto unpacker = Unpacker(packer.stream.data);
2807 
2808         unpacker.unpack(result);
2809         assert(test == result);
2810     }
2811     { // int *
2812         mixin DefinePacker;
2813 
2814         Tuple!(byte, short, int, long) result;
2815         Tuple!(byte, short, int, long) test = tuple(cast(byte)byte.min, cast(short)short.min,
2816                                                     cast(int)int.min,   cast(long)long.min);
2817 
2818         packer.pack(test);
2819 
2820         auto unpacker = Unpacker(packer.stream.data);
2821 
2822         unpacker.unpack(result);
2823         assert(test == result);
2824     }
2825     { // floating point
2826         mixin DefinePacker;
2827 
2828         static if (real.sizeof == double.sizeof || !EnableReal)
2829         {
2830             Tuple!(float, double, double) result;
2831             Tuple!(float, double, double) test = tuple(cast(float)float.min_normal, cast(double)double.max, cast(real)double.min_normal);
2832         }
2833         else
2834         {
2835             Tuple!(float, double, real) result;
2836             Tuple!(float, double, real) test = tuple(cast(float)float.min_normal, cast(double)double.max, cast(real)real.min_normal);
2837         }
2838 
2839         packer.pack(test);
2840 
2841         auto unpacker = Unpacker(packer.stream.data);
2842 
2843         unpacker.unpack(result);
2844         assert(test == result);
2845     }
2846     { // pointer
2847         mixin DefinePacker;
2848 
2849         Tuple!(ulong, long, double) origin;
2850         Tuple!(ulong, long, double) values = tuple(ulong.max, long.min, double.min_normal);
2851         Tuple!(ulong*, long*, double*) result = tuple(&origin.field[0], &origin.field[1], &origin.field[2]);
2852         Tuple!(ulong*, long*, double*) test = tuple(&values.field[0], &values.field[1], &values.field[2]);
2853 
2854         packer.pack(test);
2855 
2856         auto unpacker = Unpacker(packer.stream.data);
2857 
2858         unpacker.unpack(result);
2859         foreach (i, v; test.field)
2860             assert(*v == *result.field[i]);
2861         assert(origin == values);
2862     }
2863     { // enum
2864         enum   : float { D = 0.5 }
2865         enum E : ulong { U = 100 }
2866 
2867         mixin DefinePacker;
2868 
2869         float f = D,   resultF;
2870         E     e = E.U, resultE;
2871 
2872         packer.pack(D, e);
2873 
2874         auto unpacker = Unpacker(packer.stream.data);
2875 
2876         unpacker.unpack(resultF, resultE);
2877         assert(f == resultF);
2878         assert(e == resultE);
2879     }
2880     { // container
2881         mixin DefinePacker;
2882 
2883         Tuple!(ulong[], double[uint], string, bool[2], char[2]) test
2884             = tuple([1UL, 2], [3U:4.0, 5:6.0, 7:8.0], "MessagePack is nice!", [true, false], "D!");
2885 
2886         packer.pack(test);
2887 
2888         auto unpacker = Unpacker(packer.stream.data);
2889         Tuple!(ulong[], double[uint], string, bool[2], char[2]) result;
2890 
2891         unpacker.unpack(result);
2892         assert(test == result);
2893     }
2894     { // user defined
2895         {
2896             static struct S
2897             {
2898                 uint num;
2899 
2900                 void toMsgpack(P)(ref P p) const { p.packArray(num); }
2901                 void fromMsgpack(ref Unpacker u)
2902                 {
2903                     assert(u.beginArray() == 1);
2904                     u.unpack(num);
2905                 }
2906             }
2907 
2908             mixin DefinePacker; S result, test = S(uint.max);
2909 
2910             packer.pack(test);
2911 
2912             auto unpacker = Unpacker(packer.stream.data);
2913             unpacker.unpack(result);
2914 
2915             assert(test.num == result.num);
2916         }
2917         {
2918             static class C
2919             {
2920                 uint num;
2921 
2922                 this(uint n) { num = n; }
2923 
2924                 void toMsgpack(P)(ref P p) const { p.packArray(num - 1); }
2925                 void fromMsgpack(ref Unpacker u)
2926                 {
2927                     assert(u.beginArray() == 1);
2928                     u.unpack(num);
2929                 }
2930             }
2931 
2932             mixin DefinePacker; C result, test = new C(ushort.max);
2933 
2934             packer.pack(test);
2935 
2936             auto unpacker = Unpacker(packer.stream.data);
2937             unpacker.unpack(result, ushort.max);
2938 
2939             assert(test.num == result.num + 1);
2940         }
2941     }
2942     { // simple struct and class
2943         {
2944             static struct Simple
2945             {
2946                 uint num;
2947                 @nonPacked string str;
2948             }
2949 
2950             static struct Simple2
2951             {
2952                 @nonPacked string str;
2953                 uint num;
2954             }
2955 
2956             foreach (Type; TypeTuple!(Simple, Simple2)) {
2957                 mixin DefinePacker;
2958                 Type result, test;
2959                 test.num = uint.max;
2960                 test.str = "ignored";
2961 
2962                 packer.pack(test);
2963                 auto unpacker = Unpacker(packer.stream.data);
2964                 unpacker.unpack(result);
2965 
2966                 assert(test.num == result.num);
2967                 assert(test.str != result.str);
2968             }
2969         }
2970 
2971         static class SimpleA
2972         {
2973             bool flag = true;
2974         }
2975 
2976         static class SimpleB : SimpleA
2977         {
2978             ubyte type = 100;
2979         }
2980 
2981         static class SimpleC : SimpleB
2982         {
2983             uint num = uint.max;
2984             @nonPacked string str;
2985         }
2986 
2987         static class SimpleC2 : SimpleB
2988         {
2989             @nonPacked string str;
2990             uint num = uint.max;
2991         }
2992 
2993         { // from derived class
2994             foreach (Type; TypeTuple!(SimpleC, SimpleC2)) {
2995                 mixin DefinePacker;
2996                 Type result, test = new Type();
2997                 test.flag = false;
2998                 test.type = 99;
2999                 test.num  = uint.max / 2;
3000                 test.str  = "ignored";
3001 
3002                 packer.pack(test);
3003                 auto unpacker = Unpacker(packer.stream.data);
3004                 unpacker.unpack(result);
3005 
3006                 assert(test.flag == result.flag);
3007                 assert(test.type == result.type);
3008                 assert(test.num  == result.num);
3009                 assert(test.str  != result.str);
3010             }
3011         }
3012         { // from base class
3013             mixin DefinePacker; SimpleC test = new SimpleC();
3014 
3015             packer.pack(test);
3016 
3017             SimpleB result = new SimpleC();
3018             auto unpacker  = Unpacker(packer.stream.data);
3019 
3020             try {
3021                 unpacker.unpack(result);
3022                 assert(false);
3023             } catch (Exception e) { }
3024         }
3025         { // https://github.com/msgpack/msgpack-d/issues/16
3026             static class Issue16
3027             {
3028                 int i;
3029                 this(int i) { this.i = i; }
3030             }
3031 
3032             Issue16 c1 = new Issue16(10);
3033 
3034             try {
3035                 Issue16 c2 = null;
3036                 unpack(pack(c1), c2);
3037                 assert(false);
3038             } catch (Exception e) {}
3039 
3040             Issue16 c3 = new Issue16(20);
3041             unpack(pack(c1), c3);
3042             assert(c3.i == c1.i);
3043         }
3044     }
3045     { // variadic
3046         mixin DefinePacker;
3047 
3048         Tuple!(uint, long, double) test = tuple(uint.max, long.min, double.max);
3049 
3050         packer.pack(test);
3051 
3052         auto unpacker = Unpacker(packer.stream.data);
3053 
3054         uint u; long l; double d;
3055 
3056         unpacker.unpackArray(u, l, d);
3057         assert(test == tuple(u, l, d));
3058     }
3059     { // scan / opApply
3060         ubyte[] data;
3061         mixin DefinePacker;
3062 
3063         foreach (i; 0..2)
3064             packer.pack(tuple(1, 0.5, "Hi!"));
3065 
3066         foreach (n, d, s; &Unpacker(packer.stream.data).scan!(int, double, string)) {
3067             assert(n == 1);
3068             assert(d == 0.5);
3069             assert(s == "Hi!");
3070         }
3071     }
3072 }
3073 
3074 
3075 // Static resolution routines for Stream deserializer
3076 
3077 
3078 /**
3079  * $(D Value) is a $(D MessagePack) value representation
3080  *
3081  * Example:
3082  * -----
3083  * auto unpacker = StreamingUnpacker(pack(1, 0.1L) ~ pack(true) ~ pack("foobarbaz"));
3084  *
3085  * foreach (unpacked; unpacker) {
3086  *     if (unpacked.type == Value.Type.array) {
3087  *         foreach (obj; unpacked) {
3088  *             switch (obj.type) {
3089  *             case Value.Type.unsigned: writeln(obj.as!(uint)); break;
3090  *             case Value.Type.floating:            writeln(obj.as!(real)); break;
3091  *             defalut:
3092  *                 throw new Exception("Unknown type");
3093  *             }
3094  *         }
3095  *     } else {
3096  *         if (unpacked.type == Value.Type.boolean)
3097  *             writeln(unpacked.as!(bool));
3098  *         else
3099  *             writeln("Message: ", unpacked.as!(string));
3100  *     }
3101  * }
3102  * -----
3103  */
3104 struct Value
3105 {
3106     /**
3107      * $(D MessagePack) value type
3108      */
3109     static enum Type
3110     {
3111         nil,       /// nil(null in D)
3112         boolean,   /// true, false
3113         unsigned,  /// positive fixnum, uint 8, uint 16, uint 32, uint 64
3114         signed,    /// negative fixnum, int 8, int 16, int 32, int 64
3115         floating,  /// float, double, real
3116         array,     /// fix array, array 16, array 32
3117         map,       /// fix map, map 16, map 32
3118         raw        /// fix raw, raw 16, raw 32
3119     }
3120 
3121     /**
3122      * msgpack value representation
3123      */
3124     static union Via
3125     {
3126         bool         boolean;   /// corresponding to Type.boolean
3127         ulong        uinteger;  /// corresponding to Type.unsigned
3128         long         integer;   /// corresponding to Type.signed
3129         real         floating;  /// corresponding to Type.floating
3130         Value[]      array;     /// corresponding to Type.array
3131         Value[Value] map;       /// corresponding to Type.map
3132         ubyte[]      raw;       /// corresponding to Type.raw
3133     }
3134 
3135 
3136     Type type;  /// represents value type
3137     Via  via;   /// represents real value
3138 
3139 
3140     /**
3141      * Constructs a $(D Value) with arguments.
3142      *
3143      * Params:
3144      *  value = the real content.
3145      *  type  = the type of value.
3146      */
3147     @safe
3148     this(Type type)
3149     {
3150         this.type = type;
3151     }
3152 
3153     @safe
3154     this(typeof(null))
3155     {
3156         this(Type.nil);
3157     }
3158 
3159     /// ditto
3160     @trusted
3161     this(bool value, Type type = Type.boolean)
3162     {
3163         this(type);
3164         via.boolean = value;
3165     }
3166 
3167 
3168     /// ditto
3169     @trusted
3170     this(ulong value, Type type = Type.unsigned)
3171     {
3172         this(type);
3173         via.uinteger = value;
3174     }
3175 
3176 
3177     /// ditto
3178     @trusted
3179     this(long value, Type type = Type.signed)
3180     {
3181         this(type);
3182         via.integer = value;
3183     }
3184 
3185 
3186     /// ditto
3187     @trusted
3188     this(real value, Type type = Type.floating)
3189     {
3190         this(type);
3191         via.floating = value;
3192     }
3193 
3194 
3195     /// ditto
3196     @trusted
3197     this(Value[] value, Type type = Type.array)
3198     {
3199         this(type);
3200         via.array = value;
3201     }
3202 
3203 
3204     /// ditto
3205     @trusted
3206     this(Value[Value] value, Type type = Type.map)
3207     {
3208         this(type);
3209         via.map = value;
3210     }
3211 
3212 
3213     /// ditto
3214     @trusted
3215     this(ubyte[] value, Type type = Type.raw)
3216     {
3217         this(type);
3218         via.raw = value;
3219     }
3220 
3221     /// This is unsafe overload because using cast internally.
3222     @trusted
3223     this(string value, Type type = Type.raw)
3224     {
3225         this(type);
3226         via.raw = cast(ubyte[])value;
3227     }
3228 
3229     /**
3230      * Converts value to $(D_PARAM T) type.
3231      *
3232      * Returns:
3233      *  converted value.
3234      *
3235      * Throws:
3236      *  MessagePackException if type is mismatched.
3237      *
3238      * NOTE:
3239      *  Current implementation uses cast.
3240      */
3241     @property @trusted
3242     T as(T)() if (is(Unqual!T == bool))
3243     {
3244         if (type != Type.boolean)
3245             onCastError();
3246 
3247         return via.boolean;
3248     }
3249 
3250 
3251     /// ditto
3252     @property @trusted
3253     T as(T)() if (isIntegral!T && !is(Unqual!T == enum))
3254     {
3255         if (type == Type.unsigned)
3256             return cast(T)via.uinteger;
3257 
3258         if (type == Type.signed)
3259             return cast(T)via.integer;
3260 
3261         onCastError();
3262 
3263         assert(false);
3264     }
3265 
3266 
3267     /// ditto
3268     @property @trusted
3269     T as(T)() if (isFloatingPoint!T && !is(Unqual!T == enum))
3270     {
3271         if (type != Type.floating)
3272             onCastError();
3273 
3274         return cast(T)via.floating;
3275     }
3276 
3277 
3278     /// ditto
3279     @property @trusted
3280     T as(T)() if (is(Unqual!T == enum))
3281     {
3282         return cast(T)as!(OriginalType!T);
3283     }
3284 
3285 
3286     /// ditto
3287     @property @trusted
3288     T as(T)() if (isArray!T && !is(Unqual!T == enum))
3289     {
3290         alias typeof(T.init[0]) V;
3291 
3292         if (type == Type.nil) {
3293             static if (isDynamicArray!T) {
3294                 return null;
3295             } else {
3296                 return T.init;
3297             }
3298         }
3299 
3300         static if (isByte!V || isSomeChar!V) {
3301             if (type != Type.raw)
3302                 onCastError();
3303 
3304             static if (isDynamicArray!T) {
3305                 return cast(T)via.raw;
3306             } else {
3307                 if (via.raw.length != T.length)
3308                     onCastError();
3309 
3310                 return cast(T)(via.raw[0 .. T.length]);
3311             }
3312         } else {
3313             if (type != Type.array)
3314                 onCastError();
3315 
3316             V[] array;
3317 
3318             foreach (elem; via.array)
3319                 array ~= elem.as!(V);
3320 
3321             return array;
3322         }
3323     }
3324 
3325 
3326     /// ditto
3327     @property @trusted
3328     T as(T)() if (isAssociativeArray!T)
3329     {
3330         alias typeof(T.init.keys[0])   K;
3331         alias typeof(T.init.values[0]) V;
3332 
3333         if (type == Type.nil)
3334             return null;
3335 
3336         if (type != Type.map)
3337             onCastError();
3338 
3339         V[K] map;
3340 
3341         foreach (key, value; via.map)
3342             map[key.as!(K)] = value.as!(V);
3343 
3344         return map;
3345     }
3346 
3347 
3348     /**
3349      * Converts to $(D_PARAM T) type.
3350      *
3351      * Calling $(D fromMsgpack) if $(D_KEYWORD class) and $(D_KEYWORD struct) implement $(D fromMsgpack) method. $(D fromMsgpack) signature is:
3352      * -----
3353      * void fromMsgpack(Value value)
3354      * -----
3355      * This method assigns converted values to all members of T object if $(D_KEYWORD class) and $(D_KEYWORD struct) don't implement $(D fromMsgpack).
3356      *
3357      * Params:
3358      *  args = arguments to class constructor(class only).
3359      *
3360      * Returns:
3361      *  converted value.
3362      */
3363     @property @trusted
3364     T as(T, Args...)(Args args) if (is(Unqual!T == class))
3365     {
3366         if (type == Type.nil)
3367             return null;
3368 
3369         T object = new T(args);
3370 
3371         static if (hasMember!(T, "fromMsgpack"))
3372         {
3373             static if (__traits(compiles, { T t; t.fromMsgpack(this); })) {
3374                 object.fromMsgpack(this);
3375             } else {
3376                 static assert(0, "Failed to invoke 'fromMsgpack' on type '" ~ Unqual!T.stringof ~ "'");
3377             }
3378         } else {
3379             alias SerializingClasses!(T) Classes;
3380 
3381             if (via.array.length != SerializingMemberNumbers!(Classes))
3382                 throw new MessagePackException("The number of deserialized object member is mismatched");
3383 
3384             size_t offset;
3385             foreach (Class; Classes) {
3386                 Class obj = cast(Class)object;
3387                 foreach (i, member; obj.tupleof) {
3388                     static if (isPackedField!(Class.tupleof[i]))
3389                         obj.tupleof[i] = via.array[offset++].as!(typeof(member));
3390                 }
3391             }
3392         }
3393 
3394         return object;
3395     }
3396 
3397 
3398     /// ditto
3399     @property @trusted
3400     T as(T)() if (is(Unqual!T == struct))
3401     {
3402         T obj;
3403 
3404         static if (hasMember!(T, "fromMsgpack"))
3405         {
3406             static if (__traits(compiles, { T t; t.fromMsgpack(this); })) {
3407                 obj.fromMsgpack(this);
3408             } else {
3409                 static assert(0, "Failed to invoke 'fromMsgpack' on type '" ~ Unqual!T.stringof ~ "'");
3410             }
3411         } else {
3412             static if (isTuple!T) {
3413                 if (via.array.length != T.Types.length)
3414                     throw new MessagePackException("The number of deserialized Tuple element is mismatched");
3415 
3416                 foreach (i, Type; T.Types)
3417                     obj.field[i] = via.array[i].as!(Type);
3418             } else {  // simple struct
3419                 if (via.array.length != SerializingMemberNumbers!T)
3420                     throw new MessagePackException("The number of deserialized struct member is mismatched");
3421 
3422                 size_t offset;
3423                 foreach (i, member; obj.tupleof) {
3424                     static if (isPackedField!(T.tupleof[i]))
3425                         obj.tupleof[i] = via.array[offset++].as!(typeof(member));
3426                 }
3427             }
3428         }
3429 
3430         return obj;
3431     }
3432 
3433 
3434     /**
3435      * Special method called by $(D Packer).
3436      *
3437      * Params:
3438      *  packer = a MessagePack serializer.
3439      */
3440     void toMsgpack(Packer)(ref Packer packer) const
3441     {
3442         final switch (type) {
3443         case Type.nil:
3444             packer.packNil();
3445             break;
3446         case Type.boolean:
3447             packer.pack(via.boolean);
3448             break;
3449         case Type.unsigned:
3450             packer.pack(via.uinteger);
3451             break;
3452         case Type.signed:
3453             packer.pack(via.integer);
3454             break;
3455         case Type.floating:
3456             packer.pack(via.floating);
3457             break;
3458         case Type.raw:
3459             packer.pack(via.raw);
3460             break;
3461         case Type.array:
3462             packer.beginArray(via.array.length);
3463             foreach (elem; via.array)
3464                 elem.toMsgpack(packer);
3465             break;
3466         case Type.map:
3467             packer.beginMap(via.map.length);
3468             foreach (key, value; via.map) {
3469                 key.toMsgpack(packer);
3470                 value.toMsgpack(packer);
3471             }
3472             break;
3473         }
3474     }
3475 
3476 
3477     /**
3478      * Comparison for equality. @trusted for union.
3479      */
3480     @trusted
3481     bool opEquals(Tdummy = void)(ref const Value other) const
3482     {
3483         if (type != other.type)
3484             return false;
3485 
3486         final switch (other.type) {
3487         case Type.nil:      return true;
3488         case Type.boolean:  return opEquals(other.via.boolean);
3489         case Type.unsigned: return opEquals(other.via.uinteger);
3490         case Type.signed:   return opEquals(other.via.integer);
3491         case Type.floating: return opEquals(other.via.floating);
3492         case Type.raw:      return opEquals(other.via.raw);
3493         case Type.array:    return opEquals(other.via.array);
3494         case Type.map:      return opEquals(other.via.map);
3495         }
3496     }
3497 
3498 
3499     /// ditto
3500     @trusted
3501     bool opEquals(T : bool)(in T other) const
3502     {
3503         if (type != Type.boolean)
3504             return false;
3505 
3506         return via.boolean == other;
3507     }
3508 
3509 
3510     /// ditto
3511     @trusted
3512     bool opEquals(T : ulong)(in T other) const
3513     {
3514         static if (__traits(isUnsigned, T)) {
3515             if (type != Type.unsigned)
3516                 return false;
3517 
3518             return via.uinteger == other;
3519         } else {
3520             if (type != Type.signed)
3521                 return false;
3522 
3523             return via.integer == other;
3524         }
3525     }
3526 
3527 
3528     /// ditto
3529     @trusted
3530     bool opEquals(T : real)(in T other) const
3531     {
3532         if (type != Type.floating)
3533             return false;
3534 
3535         return via.floating == other;
3536     }
3537 
3538 
3539     /// ditto
3540     @trusted
3541     bool opEquals(T : const Value[])(in T other) const
3542     {
3543         if (type != Type.array)
3544             return false;
3545 
3546         return via.array == other;
3547     }
3548 
3549 
3550     /// ditto
3551     @trusted
3552     bool opEquals(T : const Value[Value])(in T other) const
3553     {
3554         if (type != Type.map)
3555             return false;
3556 
3557         // This comparison is instead of default comparison because 'via.map == other' raises "Access Violation".
3558         foreach (key, value; via.map) {
3559             if (key in other) {
3560                 if (other[key] != value)
3561                     return false;
3562             } else {
3563                 return false;
3564             }
3565         }
3566 
3567         return true;
3568     }
3569 
3570 
3571     /// ditto
3572     @trusted
3573     bool opEquals(T : const(ubyte)[])(in T other) const
3574     {
3575         if (type != Type.raw)
3576             return false;
3577 
3578         return via.raw == other;
3579     }
3580 
3581 
3582     /// ditto
3583     @trusted
3584     bool opEquals(T : string)(in T other) const
3585     {
3586         if (type != Type.raw)
3587             return false;
3588 
3589         return via.raw == cast(ubyte[])other;
3590     }
3591 
3592     @trusted
3593     hash_t toHash() const nothrow
3594     {
3595         static hash_t getHash(T)(T* v) @safe nothrow
3596         {
3597             return typeid(T).getHash(v);
3598         }
3599 
3600         final switch (type) {
3601             case Type.nil:      return 0;
3602             case Type.boolean:  return getHash(&via.boolean);
3603             case Type.unsigned: return getHash(&via.uinteger);
3604             case Type.signed:   return getHash(&via.integer);
3605             case Type.floating: return getHash(&via.floating);
3606             case Type.raw:      return getHash(&via.raw);
3607             case Type.array:
3608                 hash_t ret;
3609                 foreach (elem; via.array)
3610                     ret ^= elem.toHash();
3611                 return ret;
3612             case Type.map:
3613                 try {
3614                     hash_t ret;
3615                     foreach (key, value; via.map) {
3616                         ret ^= key.toHash();
3617                         ret ^= value.toHash();
3618                     }
3619                     return ret;
3620                 } catch (Exception) assert(0);
3621         }
3622     }
3623 }
3624 
3625 
3626 unittest
3627 {
3628     // nil
3629     Value value = Value(null);
3630     Value other = Value();
3631 
3632     assert(value      == other);
3633     assert(value.type == Value.Type.nil);
3634 
3635     // boolean
3636     value = Value(true);
3637     other = Value(false);
3638 
3639     assert(value           != other);
3640     assert(value.type      == Value.Type.boolean);
3641     assert(value.as!(bool) == true);
3642     assert(other           == false);
3643 
3644     try {
3645         auto b = value.as!(uint);
3646         assert(false);
3647     } catch (MessagePackException e) { }
3648 
3649     // unsigned integer
3650     value = Value(10UL);
3651     other = Value(10UL);
3652 
3653     assert(value           == other);
3654     assert(value.type      == Value.Type.unsigned);
3655     assert(value.as!(uint) == 10);
3656     assert(other           == 10UL);
3657 
3658     // signed integer
3659     value = Value(-20L);
3660     other = Value(-10L);
3661 
3662     assert(value          != other);
3663     assert(value.type     == Value.Type.signed);
3664     assert(value.as!(int) == -20);
3665     assert(other          == -10L);
3666 
3667     // enum
3668     enum E : int { F = -20 }
3669 
3670     E e = value.as!(E);
3671     assert(e == E.F);
3672 
3673     // floating point
3674     value = Value(0.1e-10L);
3675     other = Value(0.1e-20L);
3676 
3677     assert(value           != other);
3678     assert(value.type      == Value.Type.floating);
3679     assert(value.as!(real) == 0.1e-10L);
3680     assert(other           == 0.1e-20L);
3681 
3682     // raw
3683     value = Value(cast(ubyte[])[72, 105, 33]);
3684     other = Value(cast(ubyte[])[72, 105, 33]);
3685 
3686     assert(value               == other);
3687     assert(value.type          == Value.Type.raw);
3688     assert(value.as!(string)   == "Hi!");
3689     assert(value.as!(ubyte[3]) == [72, 105, 33]);
3690     assert(other               == cast(ubyte[])[72, 105, 33]);
3691 
3692     // raw with string
3693     value = Value("hello");
3694     other = Value("hello");
3695 
3696     assert(value             == other);
3697     assert(value.type        == Value.Type.raw);
3698     assert(value.as!(string) == "hello");
3699 
3700     // enum : string
3701     enum EStr : string { elem = "hello" }
3702 
3703     assert(value.as!(EStr) == EStr.elem);
3704 
3705     // array
3706     auto t = Value(cast(ubyte[])[72, 105, 33]);
3707     value = Value([t]);
3708     other = Value([t]);
3709 
3710     assert(value               == other);
3711     assert(value.type          == Value.Type.array);
3712     assert(value.as!(string[]) == ["Hi!"]);
3713     assert(other               == [t]);
3714 
3715     // map
3716     value = Value([Value(1L):Value(2L)]);
3717     other = Value([Value(1L):Value(1L)]);
3718 
3719     assert(value               != other);
3720     assert(value.type          == Value.Type.map);
3721     assert(value.as!(int[int]) == [1:2]);
3722     assert(other               == [Value(1L):Value(1L)]);
3723 
3724     value = Value(10UL);
3725 
3726     // struct
3727     static struct S
3728     {
3729         ulong num;
3730 
3731         void fromMsgpack(Value value) { num = value.via.uinteger; }
3732     }
3733 
3734     S s = value.as!(S);
3735     assert(s.num == 10);
3736 
3737     value = Value([Value(0.5f), Value(cast(ubyte[])[72, 105, 33])]);
3738 
3739     // struct
3740     static struct Simple
3741     {
3742         @nonPacked int era;
3743         double num;
3744         string msg;
3745     }
3746 
3747     Simple simple = value.as!(Simple);
3748     assert(simple.era == int.init);
3749     assert(simple.num == 0.5f);
3750     assert(simple.msg == "Hi!");
3751 
3752     value = Value(10UL);
3753 
3754     // class
3755     static class C
3756     {
3757         ulong num;
3758 
3759         void fromMsgpack(Value value) { num = value.via.uinteger; }
3760     }
3761 
3762     C c = value.as!(C);
3763     assert(c.num == 10);
3764 
3765     static class SimpleA
3766     {
3767         bool flag = true;
3768     }
3769 
3770     static class SimpleB : SimpleA
3771     {
3772         ubyte type = 100;
3773     }
3774 
3775     static class SimpleC : SimpleB
3776     {
3777         @nonPacked string str;
3778         uint num = uint.max;
3779     }
3780 
3781     value = Value([Value(false), Value(99UL), Value(cast(ulong)(uint.max / 2u))]);
3782 
3783     SimpleC sc = value.as!(SimpleC);
3784     assert(sc.flag == false);
3785     assert(sc.type == 99);
3786     assert(sc.num  == uint.max / 2);
3787     assert(sc.str.empty);
3788 
3789     // std.typecons.Tuple
3790     value = Value([Value(true), Value(1UL), Value(cast(ubyte[])"Hi!")]);
3791 
3792     auto tuple = value.as!(Tuple!(bool, uint, string));
3793     assert(tuple.field[0] == true);
3794     assert(tuple.field[1] == 1u);
3795     assert(tuple.field[2] == "Hi!");
3796 
3797     /*
3798      * non-MessagePackable object is stopped by static assert
3799      * static struct NonMessagePackable {}
3800      * auto nonMessagePackable = value.as!(NonMessagePackable);
3801      */
3802 }
3803 
3804 
3805 /**
3806  * $(D Unpacked) is a $(D Range) wrapper for stream deserialization result
3807  */
3808 struct Unpacked
3809 {
3810     Value value;  /// deserialized value
3811 
3812     alias value this;
3813 
3814 
3815     /**
3816      * Constructs a $(D Unpacked) with argument.
3817      *
3818      * Params:
3819      *  value = a deserialized value.
3820      */
3821     @safe
3822     this(ref Value value)
3823     {
3824         this.value = value;
3825     }
3826 
3827 
3828     /**
3829      * InputRange primitive operation that checks iteration state.
3830      *
3831      * Returns:
3832      *  true if there are no more elements to be iterated.
3833      */
3834     @property @trusted
3835     nothrow bool empty() const  // std.array.empty isn't nothrow function
3836     {
3837         return (value.type == Value.Type.array) && !value.via.array.length;
3838     }
3839 
3840 
3841     /**
3842      * Range primitive operation that returns the length of the range.
3843      *
3844      * Returns:
3845      *  the number of values.
3846      */
3847     @property @trusted
3848     size_t length()
3849     {
3850         return value.via.array.length;
3851     }
3852 
3853 
3854     /**
3855      * InputRange primitive operation that returns the currently iterated element.
3856      *
3857      * Returns:
3858      *  the deserialized $(D Value).
3859      */
3860     @property @trusted
3861     ref Value front()
3862     {
3863         return value.via.array.front;
3864     }
3865 
3866 
3867     /**
3868      * InputRange primitive operation that advances the range to its next element.
3869      */
3870     @trusted
3871     void popFront()
3872     {
3873         value.via.array.popFront();
3874     }
3875 
3876     /**
3877      * RandomAccessRange primitive operation.
3878      *
3879      * Returns:
3880      *  the deserialized $(D Value) at $(D_PARAM n) position.
3881      */
3882     @trusted
3883     nothrow ref Value opIndex(size_t n)
3884     {
3885         return value.via.array[n];
3886     }
3887 
3888     /**
3889      * Returns a slice of the range.
3890      *
3891      * Paramas:
3892      *  from = the start point of slicing.
3893      *  to   = the end point of slicing.
3894      *
3895      * Returns:
3896      *  the slice of Values.
3897      */
3898     @trusted
3899     Value[] opSlice(size_t from, size_t to)
3900     {
3901         return value.via.array[from..to];
3902     }
3903 
3904     /**
3905      * Range primitive operation that returns the snapshot.
3906      *
3907      * Returns:
3908      *  the snapshot of this Value.
3909      */
3910     @property @safe
3911     Unpacked save()
3912     {
3913         return Unpacked(value);
3914     }
3915 }
3916 
3917 
3918 unittest
3919 {
3920     static assert(isForwardRange!Unpacked);
3921     static assert(hasLength!Unpacked);
3922 }
3923 
3924 
3925 /**
3926  * This $(D StreamingUnpacker) is a $(D MessagePack) streaming deserializer
3927  *
3928  * This implementation enables you to load multiple objects from a stream(like network).
3929  *
3930  * Example:
3931  * -----
3932  * ...
3933  * auto unpacker = StreamingUnpacker(serializedData);
3934  * ...
3935  *
3936  * // appends new data to buffer if pre execute() call didn't finish deserialization.
3937  * unpacker.feed(newSerializedData);
3938  *
3939  * while (unpacker.execute()) {
3940  *     foreach (obj; unpacker.purge()) {
3941  *         // do stuff (obj is a Value)
3942  *     }
3943  * }
3944  *
3945  * if (unpacker.size)
3946  *     throw new Exception("Message is too large");
3947  * -----
3948  */
3949 struct StreamingUnpacker
3950 {
3951   private:
3952     /*
3953      * Context state of deserialization
3954      */
3955     enum State
3956     {
3957         HEADER = 0x00,
3958 
3959         BIN8 = 0x04,
3960         BIN16,
3961         BIN32,
3962 
3963         // Floating point, Unsigned, Signed interger (== header & 0x03)
3964         FLOAT = 0x0a,
3965         DOUBLE,
3966         UINT8,
3967         UINT16,
3968         UINT32,
3969         UINT64,
3970         INT8,
3971         INT16,
3972         INT32,
3973         INT64,
3974 
3975         // Container (== header & 0x01)
3976         STR8 = 0x19,
3977         RAW16 = 0x1a,
3978         RAW32,
3979         ARRAY16,
3980         ARRAY36,
3981         MAP16,
3982         MAP32,
3983         RAW,
3984 
3985         // D-specific type
3986         REAL
3987     }
3988 
3989 
3990     /*
3991      * Element type of container
3992      */
3993     enum ContainerElement
3994     {
3995         ARRAY_ITEM,
3996         MAP_KEY,
3997         MAP_VALUE
3998     }
3999 
4000 
4001     /*
4002      * Internal stack context
4003      */
4004     static struct Context
4005     {
4006         static struct Container
4007         {
4008             ContainerElement type;   // value container type
4009             Value            value;  // current value
4010             Value            key;    // for map value
4011             size_t           count;  // container length
4012         }
4013 
4014         State       state;  // current state of deserialization
4015         size_t      trail;  // current deserializing size
4016         size_t      top;    // current index of stack
4017         Container[] stack;  // storing values
4018     }
4019 
4020     Context context_;  // stack environment for streaming deserialization
4021 
4022     mixin InternalBuffer;
4023 
4024 
4025   public:
4026     /**
4027      * Constructs a $(D StreamingUnpacker).
4028      *
4029      * Params:
4030      *  target     = byte buffer to deserialize
4031      *  bufferSize = size limit of buffer size
4032      */
4033     @safe
4034     this(in ubyte[] target, in size_t bufferSize = 8192)
4035     {
4036         initializeBuffer(target, bufferSize);
4037         initializeContext();
4038     }
4039 
4040 
4041     /**
4042      * Forwards to deserialized object.
4043      *
4044      * Returns:
4045      *  the $(D Unpacked) object contains deserialized value.
4046      */
4047     @property @safe
4048     Unpacked unpacked()
4049     {
4050         return Unpacked(context_.stack[0].value);
4051     }
4052 
4053 
4054     /**
4055      * Clears some states for next deserialization.
4056      */
4057     @safe
4058     nothrow void clear()
4059     {
4060         initializeContext();
4061 
4062         parsed_ = 0;
4063     }
4064 
4065 
4066     /**
4067      * Convenient method for unpacking and clearing states.
4068      *
4069      * Example:
4070      * -----
4071      * foreach (obj; unpacker.purge()) {
4072      *     // do stuff
4073      * }
4074      * -----
4075      * is equivalent to
4076      * -----
4077      * foreach (obj; unpacker.unpacked) {
4078      *     // do stuff
4079      * }
4080      * unpacker.clear();
4081      * -----
4082      *
4083      * Returns:
4084      *  the $(D Unpacked) object contains deserialized value.
4085      */
4086     @safe
4087     Unpacked purge()
4088     {
4089         auto result = Unpacked(context_.stack[0].value);
4090 
4091         clear();
4092 
4093         return result;
4094     }
4095 
4096 
4097     /**
4098      * Executes deserialization.
4099      *
4100      * Returns:
4101      *  true if deserialization has been completed, otherwise false.
4102      *
4103      * Throws:
4104      *  $(D UnpackException) when parse error occurs.
4105      */
4106     bool execute()
4107     {
4108         /*
4109          * Current implementation is very dirty(goto! goto!! goto!!!).
4110          * This Complexity for performance(avoid function call).
4111          */
4112 
4113         bool   ret;
4114         size_t cur = offset_;
4115         Value obj;
4116 
4117         // restores before state
4118         auto state =  context_.state;
4119         auto trail =  context_.trail;
4120         auto top   =  context_.top;
4121         auto stack = &context_.stack;
4122 
4123         /*
4124          * Helper for container deserialization
4125          */
4126         bool startContainer(string Type)(ContainerElement type, size_t length)
4127         {
4128             mixin("callback" ~ Type ~ "((*stack)[top].value, length);");
4129 
4130             if (length == 0)
4131                 return false;
4132 
4133             (*stack)[top].type  = type;
4134             (*stack)[top].count = length;
4135             (*stack).length     = ++top + 1;
4136 
4137             return true;
4138         }
4139 
4140         // non-deserialized data is nothing
4141         if (used_ - offset_ == 0)
4142             goto Labort;
4143 
4144         do {
4145           Lstart:
4146             if (state == State.HEADER) {
4147                 const header = buffer_[cur];
4148 
4149                 if (0x00 <= header && header <= 0x7f) {         // positive
4150                     callbackUInt(obj, header);
4151                     goto Lpush;
4152                 } else if (0xe0 <= header && header <= 0xff) {  // negative
4153                     callbackInt(obj, cast(byte)header);
4154                     goto Lpush;
4155                 } else if (0xa0 <= header && header <= 0xbf) {  // fix raw
4156                     trail = header & 0x1f;
4157                     state = State.RAW;
4158                     cur++;
4159                     continue;
4160                 } else if (0x90 <= header && header <= 0x9f) {  // fix array
4161                     if (!startContainer!"Array"(ContainerElement.ARRAY_ITEM, header & 0x0f))
4162                         goto Lpush;
4163                     cur++;
4164                     continue;
4165                 } else if (0x80 <= header && header <= 0x8f) {  // fix map
4166                     if (!startContainer!"Map"(ContainerElement.MAP_KEY, header & 0x0f))
4167                         goto Lpush;
4168                     cur++;
4169                     continue;
4170                 } else {
4171                     switch (header) {
4172                     case Format.UINT8, Format.UINT16, Format.UINT32, Format.UINT64,
4173                          Format.INT8, Format.INT16, Format.INT32, Format.INT64,
4174                          Format.FLOAT, Format.DOUBLE:
4175                         trail = 1 << (header & 0x03); // computes object size
4176                         state = cast(State)(header & 0x1f);
4177                         break;
4178                     case Format.REAL:
4179                         trail = RealSize;
4180                         state = State.REAL;
4181                         break;
4182                     case Format.ARRAY16, Format.ARRAY32,
4183                          Format.MAP16, Format.MAP32:
4184                         trail = 2 << (header & 0x01);  // computes container size
4185                         state = cast(State)(header & 0x1f);
4186                         break;
4187                     // raw will become str format in new spec
4188                     case Format.STR8:
4189                     case Format.RAW16: // will be STR16
4190                     case Format.RAW32: // will be STR32
4191                         trail = 1 << ((header & 0x03) - 1);  // computes container size
4192                         state = cast(State)(header & 0x1f);
4193                         break;
4194                     case Format.BIN8, Format.BIN16, Format.BIN32:
4195                         trail = 1 << (header & 0x03);  // computes container size
4196                         state = cast(State)(header & 0x1f);
4197                         break;
4198                     case Format.NIL:
4199                         callbackNil(obj);
4200                         goto Lpush;
4201                     case Format.TRUE:
4202                         callbackBool(obj, true);
4203                         goto Lpush;
4204                     case Format.FALSE:
4205                         callbackBool(obj, false);
4206                         goto Lpush;
4207                     default:
4208                         throw new UnpackException("Unknown type");
4209                     }
4210 
4211                     cur++;
4212                     goto Lstart;
4213                 }
4214             } else {
4215                 // data lack for deserialization
4216                 if (used_ - cur < trail)
4217                     goto Labort;
4218 
4219                 const base = cur; cur += trail - 1;  // fix current position
4220 
4221                 final switch (state) {
4222                 case State.FLOAT:
4223                     _f temp;
4224 
4225                     temp.i = load32To!uint(buffer_[base..base + trail]);
4226                     callbackFloat(obj, temp.f);
4227                     goto Lpush;
4228                 case State.DOUBLE:
4229                     _d temp;
4230 
4231                     temp.i = load64To!ulong(buffer_[base..base + trail]);
4232                     callbackFloat(obj, temp.f);
4233                     goto Lpush;
4234                 case State.REAL:
4235                     const expb = base + ulong.sizeof;
4236 
4237                     version (NonX86)
4238                     {
4239                         CustomFloat!80 temp;
4240 
4241                         const frac = load64To!ulong (buffer_[base..expb]);
4242                         const exp  = load16To!ushort(buffer_[expb..expb + ushort.sizeof]);
4243 
4244                         temp.significand = frac;
4245                         temp.exponent    = exp & 0x7fff;
4246                         temp.sign        = exp & 0x8000 ? true : false;
4247 
4248                         // NOTE: temp.get!real is inf on non-x86 when deserialized value is larger than double.max.
4249                         callbackFloat(obj, temp.get!real);
4250                     }
4251                     else
4252                     {
4253                         _r temp;
4254 
4255                         temp.fraction = load64To!(typeof(temp.fraction))(buffer_[base..expb]);
4256                         temp.exponent = load16To!(typeof(temp.exponent))(buffer_[expb..expb + temp.exponent.sizeof]);
4257 
4258                         callbackFloat(obj, temp.f);
4259                     }
4260 
4261                     goto Lpush;
4262                 case State.UINT8:
4263                     callbackUInt(obj, buffer_[base]);
4264                     goto Lpush;
4265                 case State.UINT16:
4266                     callbackUInt(obj, load16To!ulong(buffer_[base..base + trail]));
4267                     goto Lpush;
4268                 case State.UINT32:
4269                     callbackUInt(obj, load32To!ulong(buffer_[base..base + trail]));
4270                     goto Lpush;
4271                 case State.UINT64:
4272                     callbackUInt(obj, load64To!ulong(buffer_[base..base + trail]));
4273                     goto Lpush;
4274                 case State.INT8:
4275                     callbackInt(obj, cast(byte)buffer_[base]);
4276                     goto Lpush;
4277                 case State.INT16:
4278                     callbackInt(obj, load16To!long(buffer_[base..base + trail]));
4279                     goto Lpush;
4280                 case State.INT32:
4281                     callbackInt(obj, load32To!long(buffer_[base..base + trail]));
4282                     goto Lpush;
4283                 case State.INT64:
4284                     callbackInt(obj, load64To!long(buffer_[base..base + trail]));
4285                     goto Lpush;
4286                 case State.RAW: Lraw:
4287                     hasRaw_ = true;
4288                     callbackRaw(obj, buffer_[base..base + trail]);
4289                     goto Lpush;
4290                 case State.STR8, State.BIN8:
4291                     trail = buffer_[base];
4292                     if (trail == 0)
4293                         goto Lraw;
4294                     state = State.RAW;
4295                     cur++;
4296                     goto Lstart;
4297                 case State.RAW16, State.BIN16:
4298                     trail = load16To!size_t(buffer_[base..base + trail]);
4299                     if (trail == 0)
4300                         goto Lraw;
4301                     state = State.RAW;
4302                     cur++;
4303                     goto Lstart;
4304                 case State.RAW32, State.BIN32:
4305                     trail = load32To!size_t(buffer_[base..base + trail]);
4306                     if (trail == 0)
4307                         goto Lraw;
4308                     state = State.RAW;
4309                     cur++;
4310                     goto Lstart;
4311                 case State.ARRAY16:
4312                     if (!startContainer!"Array"(ContainerElement.ARRAY_ITEM,
4313                                                 load16To!size_t(buffer_[base..base + trail])))
4314                         goto Lpush;
4315                     state = State.HEADER;
4316                     cur++;
4317                     continue;
4318                 case State.ARRAY36:
4319                     if (!startContainer!"Array"(ContainerElement.ARRAY_ITEM,
4320                                                 load32To!size_t(buffer_[base..base + trail])))
4321                         goto Lpush;
4322                     state = State.HEADER;
4323                     cur++;
4324                     continue;
4325                 case State.MAP16:
4326                     if (!startContainer!"Map"(ContainerElement.MAP_KEY,
4327                                               load16To!size_t(buffer_[base..base + trail])))
4328                         goto Lpush;
4329                     state = State.HEADER;
4330                     cur++;
4331                     continue;
4332                 case State.MAP32:
4333                     if (!startContainer!"Map"(ContainerElement.MAP_KEY,
4334                                               load32To!size_t(buffer_[base..base + trail])))
4335                         goto Lpush;
4336                     state = State.HEADER;
4337                     cur++;
4338                     continue;
4339                 case State.HEADER:
4340                     break;
4341                 }
4342             }
4343 
4344           Lpush:
4345             if (top == 0)
4346                 goto Lfinish;
4347 
4348             auto container = &(*stack)[top - 1];
4349 
4350             final switch (container.type) {
4351             case ContainerElement.ARRAY_ITEM:
4352                 container.value.via.array ~= obj;
4353                 if (--container.count == 0) {
4354                     obj = container.value;
4355                     top--;
4356                     goto Lpush;
4357                 }
4358                 break;
4359             case ContainerElement.MAP_KEY:
4360                 container.key  = obj;
4361                 container.type = ContainerElement.MAP_VALUE;
4362                 break;
4363             case ContainerElement.MAP_VALUE:
4364                 container.value.via.map[container.key] = obj;
4365                 if (--container.count == 0) {
4366                     obj = container.value;
4367                     top--;
4368                     goto Lpush;
4369                 }
4370                 container.type = ContainerElement.MAP_KEY;
4371             }
4372 
4373             state = State.HEADER;
4374             cur++;
4375         } while (cur < used_);
4376 
4377         goto Labort;
4378 
4379       Lfinish:
4380         (*stack)[0].value = obj;
4381         ret = true;
4382         cur++;
4383         goto Lend;
4384 
4385       Labort:
4386         ret = false;
4387 
4388       Lend:
4389         context_.state = state;
4390         context_.trail = trail;
4391         context_.top   = top;
4392         parsed_       += cur - offset_;
4393         offset_        = cur;
4394 
4395         return ret;
4396     }
4397 
4398 
4399     /**
4400      * supports foreach. One loop provides $(D Unpacked) object contains execute() result.
4401      * This is convenient in case that $(D MessagePack) values are continuous.
4402      */
4403     int opApply(scope int delegate(ref Unpacked) dg)
4404     {
4405         int result;
4406 
4407         while (execute()) {
4408             auto unpackedResult = Unpacked(context_.stack[0].value);
4409             result = dg(unpackedResult);
4410             if (result)
4411                 break;
4412 
4413             clear();
4414         }
4415 
4416         return result;
4417     }
4418 
4419 
4420   private:
4421     /*
4422      * initializes internal stack environment.
4423      */
4424     @safe
4425     nothrow void initializeContext()
4426     {
4427         context_.state        = State.HEADER;
4428         context_.trail        = 0;
4429         context_.top          = 0;
4430         context_.stack.length = 1;
4431     }
4432 }
4433 
4434 
4435 unittest
4436 {
4437     // serialize
4438     mixin DefinePacker;
4439 
4440     packer.packArray(null, true, 1, -2, "Hi!", [1], [1:1], double.max);
4441 
4442     // deserialize
4443     auto unpacker = StreamingUnpacker(packer.stream.data); unpacker.execute();
4444     auto unpacked = unpacker.purge();
4445 
4446     // Range test
4447     foreach (unused; 0..2) {
4448         uint i;
4449 
4450         foreach (obj; unpacked)
4451             i++;
4452 
4453         assert(i == unpacked.via.array.length);
4454     }
4455 
4456     auto result = unpacked.via.array;
4457 
4458     assert(result[0].type          == Value.Type.nil);
4459     assert(result[1].via.boolean   == true);
4460     assert(result[2].via.uinteger  == 1);
4461     assert(result[3].via.integer   == -2);
4462     assert(result[4].via.raw       == [72, 105, 33]);
4463     assert(result[5].as!(int[])    == [1]);
4464     assert(result[6].as!(int[int]) == [1:1]);
4465     assert(result[7].as!(double)   == double.max);
4466 }
4467 
4468 
4469 private:
4470 
4471 
4472 /*
4473  * Sets value type and value.
4474  *
4475  * Params:
4476  *  value = the value to set
4477  *  number = the content to set
4478  */
4479 @trusted
4480 void callbackUInt(ref Value value, ulong number)
4481 {
4482     value.type         = Value.Type.unsigned;
4483     value.via.uinteger = number;
4484 }
4485 
4486 
4487 /// ditto
4488 @trusted
4489 void callbackInt(ref Value value, long number)
4490 {
4491     value.type        = Value.Type.signed;
4492     value.via.integer = number;
4493 }
4494 
4495 
4496 /// ditto
4497 @trusted
4498 void callbackFloat(ref Value value, real number)
4499 {
4500     value.type         = Value.Type.floating;
4501     value.via.floating = number;
4502 }
4503 
4504 
4505 /// ditto
4506 @trusted
4507 void callbackRaw(ref Value value, ubyte[] raw)
4508 {
4509     value.type    = Value.Type.raw;
4510     value.via.raw = raw;
4511 }
4512 
4513 
4514 /// ditto
4515 @trusted
4516 void callbackArray(ref Value value, size_t length)
4517 {
4518     value.type = Value.Type.array;
4519     value.via.array.length = 0;
4520     value.via.array.reserve(length);
4521 }
4522 
4523 
4524 /// ditto
4525 @trusted
4526 void callbackMap(ref Value value, lazy size_t length)
4527 {
4528     value.type    = Value.Type.map;
4529     value.via.map = null;  // clears previous result avoiding 'Access Violation'
4530 }
4531 
4532 
4533 /// ditto
4534 @safe
4535 void callbackNil(ref Value value)
4536 {
4537     value.type = Value.Type.nil;
4538 }
4539 
4540 
4541 /// ditto
4542 @trusted
4543 void callbackBool(ref Value value, bool boolean)
4544 {
4545     value.type        = Value.Type.boolean;
4546     value.via.boolean = boolean;
4547 }
4548 
4549 
4550 unittest
4551 {
4552     Value value;
4553 
4554     // Unsigned integer
4555     callbackUInt(value, uint.max);
4556     assert(value.type         == Value.Type.unsigned);
4557     assert(value.via.uinteger == uint.max);
4558 
4559     // Signed integer
4560     callbackInt(value, int.min);
4561     assert(value.type        == Value.Type.signed);
4562     assert(value.via.integer == int.min);
4563 
4564     // Floating point
4565     callbackFloat(value, real.max);
4566     assert(value.type         == Value.Type.floating);
4567     assert(value.via.floating == real.max);
4568 
4569     // Raw
4570     callbackRaw(value, cast(ubyte[])[1]);
4571     assert(value.type    == Value.Type.raw);
4572     assert(value.via.raw == cast(ubyte[])[1]);
4573 
4574     // Array
4575     Value[] array; array.reserve(16);
4576 
4577     callbackArray(value, 16);
4578     assert(value.type               == Value.Type.array);
4579     assert(value.via.array.capacity == array.capacity);
4580 
4581     // Map
4582     Value[Value] map;
4583 
4584     callbackMap(value, 16);
4585     assert(value.type    == Value.Type.map);
4586     assert(value.via.map == null);
4587 
4588     // NIL
4589     callbackNil(value);
4590     assert(value.type == Value.Type.nil);
4591 
4592     // Bool
4593     callbackBool(value, true);
4594     assert(value.type        == Value.Type.boolean);
4595     assert(value.via.boolean == true);
4596 }
4597 
4598 
4599 private:
4600 
4601 
4602 /*
4603  * A callback for type-mismatched error in cast conversion.
4604  */
4605 @safe
4606 pure void onCastError()
4607 {
4608     throw new MessagePackException("Attempt to cast with another type");
4609 }
4610 
4611 
4612 /*
4613  * A callback for type-mismatched error in deserialization process.
4614  */
4615 @safe
4616 pure void onInvalidType()
4617 {
4618     throw new MessagePackException("Attempt to unpack with non-compatible type");
4619 }
4620 
4621 
4622 public:
4623 
4624 
4625 /*
4626  * Handy helper for creating MessagePackable object.
4627  *
4628  * toMsgpack / fromMsgpack are special methods for serialization / deserialization.
4629  * This template provides those methods to struct/class.
4630  *
4631  * Example:
4632  * -----
4633  * struct S
4634  * {
4635  *     int num; string str;
4636  *
4637  *     // http://d.puremagic.com/issues/show_bug.cgi?id = 1099
4638  *     mixin MessagePackable;  // all members
4639  *     // mixin MessagePackable!("num");  // num only
4640  * }
4641  * -----
4642  *
4643  * Defines those methods manually if you treat complex data-structure.
4644  */
4645 mixin template MessagePackable(Members...)
4646 {
4647     static if (Members.length == 0) {
4648         /**
4649          * Serializes members using $(D_PARAM packer).
4650          *
4651          * Params:
4652          *  packer = the serializer to pack.
4653          */
4654         void toMsgpack(Packer)(ref Packer packer, bool withFieldName = false) const
4655         {
4656             if (withFieldName) {
4657                 packer.beginMap(this.tupleof.length);
4658                 foreach (i, member; this.tupleof) {
4659                     packer.pack(getFieldName!(typeof(this), i));
4660                     packer.pack(member);
4661                 }
4662             } else {
4663                 packer.beginArray(this.tupleof.length);
4664                 foreach (member; this.tupleof)
4665                     packer.pack(member);
4666             }
4667         }
4668 
4669 
4670         /**
4671          * Deserializes $(D MessagePack) object to members using Value.
4672          *
4673          * Params:
4674          *  value = the MessagePack value to unpack.
4675          *
4676          * Throws:
4677          *  MessagePackException if $(D_PARAM value) is not an Array type.
4678          */
4679         void fromMsgpack(Value value)
4680         {
4681             // enables if std.contracts.enforce is moved to object_.d
4682             // enforceEx!MessagePackException(value.type == Value.Type.array, "Value must be Array type");
4683             if (value.type != Value.Type.array)
4684                 throw new MessagePackException("Value must be an Array type");
4685             if (value.via.array.length != this.tupleof.length)
4686                 throw new MessagePackException("The size of deserialized value is mismatched");
4687 
4688             foreach (i, member; this.tupleof)
4689                 this.tupleof[i] = value.via.array[i].as!(typeof(member));
4690         }
4691 
4692 
4693         /**
4694          * Deserializes $(D MessagePack) object to members using direct-conversion deserializer.
4695          *
4696          * Params:
4697          *  value = the reference to direct-conversion deserializer.
4698          *
4699          * Throws:
4700          *  MessagePackException if the size of deserialized value is mismatched.
4701          */
4702         void fromMsgpack(ref Unpacker unpacker)
4703         {
4704             auto length = unpacker.beginArray();
4705             if (length != this.tupleof.length)
4706                 throw new MessagePackException("The size of deserialized value is mismatched");
4707 
4708             foreach (i, member; this.tupleof)
4709                 unpacker.unpack(this.tupleof[i]);
4710         }
4711     } else {
4712         /**
4713          * Member selecting version of toMsgpack.
4714          */
4715         void toMsgpack(Packer)(ref Packer packer, bool withFieldName = false) const
4716         {
4717             if (withFieldName) {
4718                 packer.beginMap(Members.length);
4719                 foreach (member; Members) {
4720                     packer.pack(member);
4721                     packer.pack(mixin(member));
4722                 }
4723             } else {
4724                 packer.beginArray(Members.length);
4725                 foreach (member; Members)
4726                     packer.pack(mixin(member));
4727             }
4728         }
4729 
4730 
4731         /**
4732          * Member selecting version of fromMsgpack for Value.
4733          */
4734         void fromMsgpack(Value value)
4735         {
4736             if (value.type != Value.Type.array)
4737                 throw new MessagePackException("Value must be an Array type");
4738             if (value.via.array.length != Members.length)
4739                 throw new MessagePackException("The size of deserialized value is mismatched");
4740 
4741             foreach (i, member; Members)
4742                 mixin(member ~ "= value.via.array[i].as!(typeof(" ~ member ~ "));");
4743         }
4744 
4745 
4746         /**
4747          * Member selecting version of fromMsgpack for direct-converion deserializer.
4748          */
4749         void fromMsgpack(ref Unpacker unpacker)
4750         {
4751             auto length = unpacker.beginArray();
4752             if (length != Members.length)
4753                 throw new MessagePackException("The size of deserialized value is mismatched");
4754 
4755             foreach (member; Members)
4756                 unpacker.unpack(mixin(member));
4757         }
4758     }
4759 }
4760 
4761 
4762 unittest
4763 {
4764     { // all members
4765         /*
4766          * Comment out because "src/msgpack.d(4048): Error: struct msgpack.__unittest16.S no size yet for forward reference" occurs
4767          */
4768         static struct S
4769         {
4770             uint num; string str;
4771             mixin MessagePackable;
4772         }
4773 
4774         mixin DefinePacker;
4775 
4776         S orig = S(10, "Hi!"); orig.toMsgpack(packer);
4777 
4778         { // stream
4779             auto unpacker = StreamingUnpacker(packer.stream.data); unpacker.execute();
4780 
4781             S result; result.fromMsgpack(unpacker.unpacked);
4782 
4783             assert(result.num == 10);
4784             assert(result.str == "Hi!");
4785         }
4786         { // direct conversion
4787             auto unpacker = Unpacker(packer.stream.data);
4788 
4789             S result; unpacker.unpack(result);
4790 
4791             assert(result.num == 10);
4792             assert(result.str == "Hi!");
4793         }
4794     }
4795     { // member select
4796         static class C
4797         {
4798             uint num; string str;
4799 
4800             this() {}
4801             this(uint n, string s) { num = n; str = s; }
4802 
4803             mixin MessagePackable!("num");
4804         }
4805 
4806         mixin DefinePacker;
4807 
4808         C orig = new C(10, "Hi!"); orig.toMsgpack(packer);
4809 
4810         { // stream
4811             auto unpacker = StreamingUnpacker(packer.stream.data); unpacker.execute();
4812 
4813             C result = new C; result.fromMsgpack(unpacker.unpacked);
4814 
4815             assert(result.num == 10);
4816         }
4817         { // direct conversion
4818             auto unpacker = Unpacker(packer.stream.data);
4819 
4820             C result; unpacker.unpack(result);
4821 
4822             assert(result.num == 10);
4823         }
4824     }
4825 }
4826 
4827 
4828 private:
4829 
4830 
4831 // Common and system dependent operations
4832 
4833 
4834 /*
4835  * MessagePack type-information format
4836  *
4837  * See_Also:
4838  *  $(LINK2 http://redmine.msgpack.org/projects/msgpack/wiki/FormatSpec, MessagePack Specificaton)
4839  */
4840 enum Format : ubyte
4841 {
4842     // unsinged integer
4843     UINT8  = 0xcc,  // ubyte
4844     UINT16 = 0xcd,  // ushort
4845     UINT32 = 0xce,  // uint
4846     UINT64 = 0xcf,  // ulong
4847 
4848     // signed integer
4849     INT8  = 0xd0,   // byte
4850     INT16 = 0xd1,   // short
4851     INT32 = 0xd2,   // int
4852     INT64 = 0xd3,   // long
4853 
4854     // floating point
4855     FLOAT  = 0xca,  // float
4856     DOUBLE = 0xcb,  // double
4857 
4858     // raw byte
4859     RAW   = 0xa0,
4860     RAW16 = 0xda,
4861     RAW32 = 0xdb,
4862 
4863     // bin type
4864     BIN8  = 0xc4,
4865     BIN16 = 0xc5,
4866     BIN32 = 0xc6,
4867 
4868     // str type
4869     STR8  = 0xd9,
4870     //STR16 = 0xda,
4871     //STR32 = 0xdb,
4872 
4873     // array
4874     ARRAY   = 0x90,
4875     ARRAY16 = 0xdc,
4876     ARRAY32 = 0xdd,
4877 
4878     // map
4879     MAP   = 0x80,
4880     MAP16 = 0xde,
4881     MAP32 = 0xdf,
4882 
4883     // other
4884     NIL   = 0xc0,   // null
4885     TRUE  = 0xc3,
4886     FALSE = 0xc2,
4887 
4888     // real (This format is D only!)
4889     REAL = 0xd4
4890 }
4891 
4892 
4893 /*
4894  * For float type serialization / deserialization
4895  */
4896 union _f
4897 {
4898     float f;
4899     uint  i;
4900 }
4901 
4902 
4903 /*
4904  * For double type serialization / deserialization
4905  */
4906 union _d
4907 {
4908     double f;
4909     ulong  i;
4910 }
4911 
4912 
4913 /*
4914  * For real type serialization / deserialization
4915  *
4916  * 80-bit real is padded to 12 bytes(Linux) and 16 bytes(Mac).
4917  * http://lists.puremagic.com/pipermail/digitalmars-d/2010-June/077394.html
4918  */
4919 union _r
4920 {
4921     real f;
4922 
4923     struct
4924     {
4925         ulong  fraction;
4926         ushort exponent;  // includes sign
4927     }
4928 }
4929 
4930 enum RealSize = 10;  // Real size is 80bit
4931 
4932 
4933 /*
4934  * Detects whether $(D_PARAM T) is a built-in byte type.
4935  */
4936 template isByte(T)
4937 {
4938     enum isByte = staticIndexOf!(Unqual!T, byte, ubyte) >= 0;
4939 }
4940 
4941 
4942 unittest
4943 {
4944     static assert(isByte!(byte));
4945     static assert(isByte!(const(byte)));
4946     static assert(isByte!(ubyte));
4947     static assert(isByte!(immutable(ubyte)));
4948     static assert(!isByte!(short));
4949     static assert(!isByte!(char));
4950     static assert(!isByte!(string));
4951 }
4952 
4953 
4954 /*
4955  * Gets asterisk string from pointer type
4956  */
4957 template AsteriskOf(T)
4958 {
4959     static if (is(T P == U*, U))
4960         enum AsteriskOf = "*" ~ AsteriskOf!U;
4961     else
4962         enum AsteriskOf = "";
4963 }
4964 
4965 /**
4966  * Get the number of member to serialize.
4967  */
4968 template SerializingMemberNumbers(Classes...)
4969 {
4970     static if (Classes.length == 0)
4971         enum SerializingMemberNumbers = 0;
4972     else
4973         enum SerializingMemberNumbers = Filter!(isPackedField, Classes[0].tupleof).length + SerializingMemberNumbers!(Classes[1..$]);
4974 }
4975 
4976 /**
4977  * Get derived classes with serialization-order
4978  */
4979 template SerializingClasses(T)
4980 {
4981     // There is no information in Object type. Currently disable Object serialization.
4982     static if (is(T == Object))
4983         static assert(false, "Object type serialization doesn't support yet. Please define toMsgpack/fromMsgpack and use cast");
4984     else
4985         alias TypeTuple!(Reverse!(Erase!(Object, BaseClassesTuple!(T))), T) SerializingClasses;
4986 }
4987 
4988 
4989 /**
4990  * Get a field name of class or struct.
4991  */
4992 template getFieldName(Type, size_t i)
4993 {
4994     import std.conv : text;
4995 
4996     static assert((is(Unqual!Type == class) || is(Unqual!Type == struct)), "Type must be class or struct: type = " ~ Type.stringof);
4997     static assert(i < Type.tupleof.length, text(Type.stringof, " has ", Type.tupleof.length, " attributes: given index = ", i));
4998 
4999     enum getFieldName = __traits(identifier, Type.tupleof[i]);
5000 }
5001 
5002 
5003 version (LittleEndian)
5004 {
5005     /*
5006      * Converts $(value) to different Endian.
5007      *
5008      * Params:
5009      *  value = the LittleEndian value to convert.
5010      *
5011      * Returns:
5012      *  the converted value.
5013      */
5014     @trusted
5015     ushort convertEndianTo(size_t Bit, T)(in T value) if (Bit == 16)
5016     {
5017         return ntohs(cast(ushort)value);
5018     }
5019 
5020 
5021     // ditto
5022     @trusted
5023     uint convertEndianTo(size_t Bit, T)(in T value) if (Bit == 32)
5024     {
5025         return ntohl(cast(uint)value);
5026     }
5027 
5028 
5029     // ditto
5030     @trusted
5031     ulong convertEndianTo(size_t Bit, T)(in T value) if (Bit == 64)
5032     {
5033         // dmd has convert function?
5034         return ((((cast(ulong)value) << 56) & 0xff00000000000000UL) |
5035                 (((cast(ulong)value) << 40) & 0x00ff000000000000UL) |
5036                 (((cast(ulong)value) << 24) & 0x0000ff0000000000UL) |
5037                 (((cast(ulong)value) <<  8) & 0x000000ff00000000UL) |
5038                 (((cast(ulong)value) >>  8) & 0x00000000ff000000UL) |
5039                 (((cast(ulong)value) >> 24) & 0x0000000000ff0000UL) |
5040                 (((cast(ulong)value) >> 40) & 0x000000000000ff00UL) |
5041                 (((cast(ulong)value) >> 56) & 0x00000000000000ffUL));
5042     }
5043 
5044 
5045     unittest
5046     {
5047         assert(convertEndianTo!16(0x0123)             == 0x2301);
5048         assert(convertEndianTo!32(0x01234567)         == 0x67452301);
5049         assert(convertEndianTo!64(0x0123456789abcdef) == 0xefcdab8967452301);
5050     }
5051 
5052 
5053     /*
5054      * Comapatible for BigEndian environment.
5055      */
5056     ubyte take8from(size_t bit = 8, T)(T value)
5057     {
5058         static if (bit == 8 || bit == 16 || bit == 32 || bit == 64)
5059             return (cast(ubyte*)&value)[0];
5060         else
5061             static assert(false, bit.stringof ~ " is not support bit width.");
5062     }
5063 
5064 
5065     unittest
5066     {
5067         foreach (Integer; TypeTuple!(ubyte, ushort, uint, ulong)) {
5068             assert(take8from!8 (cast(Integer)0x01)               == 0x01);
5069             assert(take8from!16(cast(Integer)0x0123)             == 0x23);
5070             assert(take8from!32(cast(Integer)0x01234567)         == 0x67);
5071             assert(take8from!64(cast(Integer)0x0123456789abcdef) == 0xef);
5072         }
5073     }
5074 }
5075 else
5076 {
5077     /*
5078      * Comapatible for LittleEndian environment.
5079      */
5080     @safe
5081     ushort convertEndianTo(size_t Bit, T)(in T value) if (Bit == 16)
5082     {
5083         return cast(ushort)value;
5084     }
5085 
5086 
5087     // ditto
5088     @safe
5089     uint convertEndianTo(size_t Bit, T)(in T value) if (Bit == 32)
5090     {
5091         return cast(uint)value;
5092     }
5093 
5094 
5095     // ditto
5096     @safe
5097     ulong convertEndianTo(size_t Bit, T)(in T value) if (Bit == 64)
5098     {
5099         return cast(ulong)value;
5100     }
5101 
5102 
5103     unittest
5104     {
5105         assert(convertEndianTo!16(0x0123)       == 0x0123);
5106         assert(convertEndianTo!32(0x01234567)   == 0x01234567);
5107         assert(convertEndianTo!64(0x0123456789) == 0x0123456789);
5108     }
5109 
5110 
5111     /*
5112      * Takes 8bit from $(D_PARAM value)
5113      *
5114      * Params:
5115      *  value = the content to take.
5116      *
5117      * Returns:
5118      *  the 8bit value corresponding $(D_PARAM bit) width.
5119      */
5120     ubyte take8from(size_t bit = 8, T)(T value)
5121     {
5122         static if (bit == 8)
5123             return (cast(ubyte*)&value)[0];
5124         else static if (bit == 16)
5125             return (cast(ubyte*)&value)[1];
5126         else static if (bit == 32)
5127             return (cast(ubyte*)&value)[3];
5128         else static if (bit == 64)
5129             return (cast(ubyte*)&value)[7];
5130         else
5131             static assert(false, bit.stringof ~ " is not support bit width.");
5132     }
5133 
5134 
5135     unittest
5136     {
5137         foreach (Integer; TypeTuple!(ubyte, ushort, uint, ulong)) {
5138             assert(take8from!8 (cast(Integer)0x01)               == 0x01);
5139             assert(take8from!16(cast(Integer)0x0123)             == 0x23);
5140             assert(take8from!32(cast(Integer)0x01234567)         == 0x67);
5141             assert(take8from!64(cast(Integer)0x0123456789abcdef) == 0xef);
5142         }
5143     }
5144 }
5145 
5146 
5147 /*
5148  * Loads $(D_PARAM T) type value from $(D_PARAM buffer).
5149  *
5150  * Params:
5151  *  buffer = the serialized contents.
5152  *
5153  * Returns:
5154  *  the Endian-converted value.
5155  */
5156 T load16To(T)(ubyte[] buffer)
5157 {
5158     return cast(T)(convertEndianTo!16(*cast(ushort*)buffer.ptr));
5159 }
5160 
5161 
5162 // ditto
5163 T load32To(T)(ubyte[] buffer)
5164 {
5165     return cast(T)(convertEndianTo!32(*cast(uint*)buffer.ptr));
5166 }
5167 
5168 
5169 // ditto
5170 T load64To(T)(ubyte[] buffer)
5171 {
5172     return cast(T)(convertEndianTo!64(*cast(ulong*)buffer.ptr));
5173 }