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 }