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