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 }