1 module lmpl4d.common; 2 3 import 4 core.bitop, 5 std.container.array; 6 7 package import 8 std.meta, 9 std.traits, 10 std.typecons; 11 12 version(EnableReal) 13 enum EnableReal = true; 14 else 15 enum EnableReal = false; 16 17 version(NoPackingStruct) {} 18 else { 19 struct nonPacked {} 20 21 package enum isPackedField(alias field) = staticIndexOf!(nonPacked, __traits(getAttributes, field)) == -1 22 && !isSomeFunction!(typeof(field)); 23 24 /** 25 * Get the number of member to serialize. 26 */ 27 template NumOfSerializingMembers(Classes...) 28 { 29 static if (Classes.length) 30 enum NumOfSerializingMembers = Filter!(isPackedField, Classes[0].tupleof).length + 31 NumOfSerializingMembers!(Classes[1..$]); 32 else 33 enum NumOfSerializingMembers = 0; 34 } 35 } 36 37 package: 38 39 enum isSomeArray(T) = (isArray!T || isInstanceOf!(Array, T)) && !is(Unqual!T == enum); 40 41 static if (real.sizeof == double.sizeof) { 42 // for 80bit real inter-operation on non-x86 CPU 43 version = NonX86; 44 45 import std.numeric; 46 } 47 48 /** 49 * For float/double type (de)serialization 50 */ 51 union _f { float f; uint i; } 52 53 union _d { double f; ulong i; } 54 55 /** 56 * For real type (de)serialization 57 * 58 * 80-bit real is padded to 12 bytes(Linux) and 16 bytes(Mac). 59 * http://lists.puremagic.com/pipermail/digitalmars-d/2010-June/077394.html 60 */ 61 union _r 62 { 63 real f; 64 65 struct 66 { 67 ulong fraction; 68 ushort exponent; // includes sign 69 } 70 } 71 72 enum isRawByte(T) = is(Unqual!T : ubyte) || isSomeChar!T; 73 74 /** 75 * Gets asterisk string from pointer type 76 */ 77 template AsteriskOf(T) 78 { 79 static if (is(T P == U*, U)) 80 enum AsteriskOf = "*" ~ AsteriskOf!U; 81 else 82 enum AsteriskOf = ""; 83 } 84 85 version(unittest) 86 void fillData(T)(ref T data) 87 { 88 import core.stdc.stdlib; 89 import std.datetime.systime; 90 91 srand(cast(uint)Clock.currStdTime); 92 foreach(ref x; data) 93 x = cast(ubyte)rand(); 94 } 95 96 public: 97 98 version (LittleEndian) 99 { 100 /* 101 * Converts $(value) to different Endian. 102 * 103 * Params: 104 * value = the LittleEndian value to convert. 105 * 106 * Returns: 107 * the converted value. 108 */ 109 @trusted 110 ushort convertEndianTo(size_t Bit, T)(in T value) if (Bit == 16) 111 { 112 return byteswap(cast(ushort)value); 113 } 114 115 // ditto 116 @trusted 117 uint convertEndianTo(size_t Bit, T)(in T value) if (Bit == 32) 118 { 119 return bswap(cast(uint)value); 120 } 121 122 // ditto 123 @trusted 124 ulong convertEndianTo(size_t Bit, T)(in T value) if (Bit == 64) 125 { 126 return bswap(value); 127 } 128 129 unittest 130 { 131 assert(convertEndianTo!16(0x0123) == 0x2301); 132 assert(convertEndianTo!32(0x01234567) == 0x67452301); 133 assert(convertEndianTo!64(0x0123456789abcdef) == 0xefcdab8967452301); 134 } 135 136 /* 137 * Comapatible for BigEndian environment. 138 */ 139 ubyte take8from(size_t bit = 8, T)(T value) 140 if (bit == 8 || bit == 16 || bit == 32 || bit == 64) 141 { 142 return (cast(ubyte*)&value)[0]; 143 } 144 } 145 else 146 { 147 /* 148 * Comapatible for LittleEndian environment. 149 */ 150 @safe 151 ushort convertEndianTo(size_t bit, T)(in T value) 152 if (bit == 16 || bit == 32 || bit == 64) 153 { 154 static if (bit == 16) 155 alias U = ushort; 156 else static if (bit == 32) 157 alias U = uint; 158 else 159 alias U = ulong; 160 return cast(U)value; 161 } 162 163 unittest 164 { 165 assert(convertEndianTo!16(0x0123) == 0x0123); 166 assert(convertEndianTo!32(0x01234567) == 0x01234567); 167 assert(convertEndianTo!64(0x0123456789) == 0x0123456789); 168 } 169 170 /* 171 * Takes 8bit from $(D_PARAM value) 172 * 173 * Params: 174 * value = the content to take. 175 * 176 * Returns: 177 * the 8bit value corresponding $(D_PARAM bit) width. 178 */ 179 ubyte take8from(size_t bit = 8, T)(T value) 180 if (bit == 8 || bit == 16 || bit == 32 || bit == 64) 181 { 182 return (cast(ubyte*)&value)[(bit >> 3) - 1]; 183 } 184 } 185 186 unittest 187 { 188 foreach (Int; AliasSeq!(ubyte, ushort, uint, ulong)) { 189 assert(take8from!8 (cast(Int)0x01) == 0x01); 190 assert(take8from!16(cast(Int)0x0123) == 0x23); 191 assert(take8from!32(cast(Int)0x01234567) == 0x67); 192 assert(take8from!64(cast(Int)0x0123456789abcdef) == 0xef); 193 } 194 } 195 196 enum isInputBuffer(R, E) = __traits(compiles, (R r, size_t i) { E e = r[i++]; }); 197 enum isOutputBuffer(R, E) = 198 __traits(compiles, (R r, E e) { r.reserve(1); r ~= e; r = R(&r[0], 1, 1); }) || __traits(compiles, 199 (R r, E e) { size_t sz = r.length; r.length = sz + E.sizeof; *cast(Unqual!E*)&r[sz] = e; }) 200 || __traits(compiles, (R r, E e) { *cast(Unqual!E*)&r[0] = e; r += E.sizeof; }); 201 202 unittest 203 { 204 static assert(!isInputBuffer!(void[], ubyte)); 205 static assert(isInputBuffer!(ubyte[9], ubyte)); 206 static assert(isInputBuffer!(ubyte[], ubyte)); 207 static assert(isInputBuffer!(ubyte*, ubyte)); 208 static assert(isInputBuffer!(Array!ubyte, ubyte)); 209 static assert(!isInputBuffer!(ubyte, ubyte)); 210 static assert(!isInputBuffer!(int[], ubyte)); 211 static assert(isOutputBuffer!(void[], ubyte)); 212 static assert(!isOutputBuffer!(ubyte[9], ubyte)); 213 static assert(isOutputBuffer!(ubyte[], ubyte)); 214 static assert(isOutputBuffer!(ubyte*, ubyte)); 215 static assert(isOutputBuffer!(Array!ubyte, ubyte)); 216 static assert(isOutputBuffer!(int[], ubyte)); 217 } 218 219 version(betterC){}else { 220 pure: 221 /** 222 * $(D MessagePackException) is a root Exception for MessagePack related operation. 223 */ 224 class MessagePackException : Exception 225 { 226 this(string msg) { super(msg); } 227 } 228 /** 229 * $(D UnpackException) is thrown on deserialization failure 230 */ 231 class UnpackException : MessagePackException 232 { 233 this(string msg) { super(msg); } 234 } 235 } 236 237 nothrow @nogc pure: 238 239 /** 240 * MessagePack type-information format 241 * 242 * See_Also: 243 * $(LINK2 http://redmine.msgpack.org/projects/msgpack/wiki/FormatSpec, MessagePack Specificaton) 244 */ 245 enum Format : ubyte 246 { 247 NONE, 248 249 // unsinged integer 250 UINT8 = 0xcc, // ubyte 251 UINT16 = 0xcd, // ushort 252 UINT32 = 0xce, // uint 253 UINT64 = 0xcf, // ulong 254 255 // signed integer 256 INT8 = 0xd0, // byte 257 INT16 = 0xd1, // short 258 INT32 = 0xd2, // int 259 INT64 = 0xd3, // long 260 261 // floating point 262 FLOAT = 0xca, // float 263 DOUBLE = 0xcb, // double 264 265 // raw byte 266 RAW = 0xa0, 267 RAW16 = 0xda, 268 RAW32 = 0xdb, 269 270 // bin type 271 BIN8 = 0xc4, 272 BIN16 = 0xc5, 273 BIN32 = 0xc6, 274 275 // ext type 276 EXT = 0xd4, // fixext 1/2/4/8/16 277 EXT8 = 0xc7, 278 EXT16 = 0xc8, 279 EXT32 = 0xc9, 280 281 // str type 282 STR8 = 0xd9, 283 //STR16 = 0xda, 284 //STR32 = 0xdb, 285 286 // array 287 ARRAY = 0x90, 288 ARRAY16 = 0xdc, 289 ARRAY32 = 0xdd, 290 291 // map 292 MAP = 0x80, 293 MAP16 = 0xde, 294 MAP32 = 0xdf, 295 296 // other 297 NIL = 0xc0, // null 298 TRUE = 0xc3, 299 FALSE = 0xc2, 300 301 // real (This format is D only!) 302 REAL = 0xd4 303 } 304 305 /* 306 * Calculates the format size of container length. 307 */ 308 size_t calculateSize(bool rawType = false)(in size_t length) 309 { 310 enum S = rawType ? 32 : 16; 311 return length < S ? 0 : length <= ushort.max ? ushort.sizeof : uint.sizeof; 312 } 313 314 /// Adaptive Output Buffer 315 struct AOutputBuf(Stream, T = ubyte) if(isOutputBuffer!(Stream, T)) 316 { 317 @property ref Stream buf() { return *arr; } 318 319 @property ref const(Stream) buf() const { return *arr; } 320 321 Stream* arr; 322 this(ref Stream array) { arr = &array; } 323 324 ref const(Stream) opOpAssign(string op : "~")(inout(T[]) rhs) { 325 buf.reserve(buf.length + rhs.length); 326 foreach(ref elem; rhs) 327 this ~= elem; 328 return buf; 329 } 330 331 ref const(Stream) opOpAssign(string op : "~", U)(U rhs) if(!isDynamicArray!U) { 332 static if (isPointer!Stream) 333 size_t sz = 0; 334 else 335 size_t sz = buf.length; 336 static if (__traits(compiles, buf.length = buf.length + 1)) 337 buf.length = sz + U.sizeof; 338 else { 339 // for Dvector!T 340 buf.reserve(sz + U.sizeof); 341 buf = Stream(&buf[0], sz + U.sizeof, buf.capacity); 342 } 343 *cast(Unqual!U*)&buf[sz] = rhs; 344 static if (isPointer!Stream) buf += U.sizeof; 345 return buf; 346 } 347 348 // for Array!T 349 static if (!__traits(compiles, buf[0 .. 2] == [0, 1])) @nogc { 350 T[] opSlice() 351 { 352 return (&buf[0])[0..buf.length]; 353 } 354 355 T[] opSlice(size_t i, size_t j) 356 { 357 return (&buf[0])[i..j]; 358 } 359 } 360 361 alias buf this; 362 } 363 364 version(unittest) 365 { 366 import 367 std.container.array, 368 core.stdc.string; 369 370 package: 371 template DefinePacker() 372 { 373 auto arr = Array!ubyte(); 374 auto packer = Packer!(Array!ubyte)(arr); 375 } 376 template TestUnpacker() 377 { 378 auto unpacker = Unpacker!()(packer.buf[]); 379 static if (is(typeof(test))) { 380 auto result = unpacker.unpack!(typeof(test)); 381 auto testfunc = { 382 import std.conv : text; 383 assert(result == test, text(test, "\nExpected: ", result)); 384 return 0; 385 }(); 386 } 387 } 388 }