1 /**********************************************************\ 2 | | 3 | hprose | 4 | | 5 | Official WebSite: http://www.hprose.com/ | 6 | http://www.hprose.org/ | 7 | | 8 \**********************************************************/ 9 10 /**********************************************************\ 11 * * 12 * hprose/io/reader.d * 13 * * 14 * hprose reader library for D. * 15 * * 16 * LastModified: Aug 3, 2016 * 17 * Author: Ma Bingyao <andot@hprose.com> * 18 * * 19 \**********************************************************/ 20 21 module hprose.io.reader; 22 23 @trusted: 24 25 import hprose.io.bytes; 26 import hprose.io.classmanager; 27 import hprose.io.common; 28 import hprose.io.tags; 29 import std.algorithm; 30 import std.bigint; 31 import std.container; 32 import std.conv; 33 import std.datetime; 34 import std.exception; 35 import std.json; 36 import std.math; 37 import std.stdio; 38 import std.string; 39 import std.traits; 40 import std.typecons; 41 import std.utf; 42 import std.uuid; 43 import std.variant; 44 45 private { 46 interface ReaderRefer { 47 void set(Variant value); 48 Variant read(int index); 49 void reset(); 50 } 51 52 final class FakeReaderRefer : ReaderRefer { 53 void set(Variant value) {} 54 Variant read(int index) { 55 throw new Exception("Unexcepted serialize tag '" ~ TagRef ~ "' in stream"); 56 } 57 void reset() {} 58 } 59 60 final class RealReaderRefer : ReaderRefer { 61 private { 62 Variant[] _references; 63 } 64 void set(Variant value) { 65 _references ~= value; 66 } 67 Variant read(int index) { 68 return _references[index]; 69 } 70 void reset() { 71 _references = null; 72 } 73 } 74 } 75 76 class RawReader { 77 protected { 78 BytesIO _bytes; 79 } 80 private { 81 int stoi(string str) { 82 if (str.length == 0) return 0; 83 return to!int(str); 84 } 85 void readNumberRaw(BytesIO bytes) { 86 bytes.write(_bytes.readBytes(TagSemicolon)); 87 } 88 void readDateTimeRaw(BytesIO bytes) { 89 bytes.write(_bytes.readBytes(TagSemicolon, TagUTC)); 90 } 91 void readUTF8CharRaw(BytesIO bytes) { 92 bytes.write(_bytes.readUTF8Char()); 93 } 94 void readBytesRaw(BytesIO bytes) { 95 string len = cast(string)_bytes.readUntil(TagQuote); 96 bytes.write(len).write(TagQuote).write(_bytes.read(stoi(len))).write(TagQuote); 97 _bytes.skip(1); 98 } 99 void readStringRaw(BytesIO bytes) { 100 string len = cast(string)_bytes.readUntil(TagQuote); 101 bytes.write(len).write(TagQuote).write(_bytes.readString(stoi(len))).write(TagQuote); 102 _bytes.skip(1); 103 } 104 void readGuidRaw(BytesIO bytes) { 105 bytes.write(_bytes.read(38)); 106 } 107 void readComplexRaw(BytesIO bytes) { 108 bytes.write(_bytes.readBytes(TagOpenbrace)); 109 ubyte tag; 110 while ((tag = _bytes.read()) != TagClosebrace) { 111 readRaw(bytes, tag); 112 } 113 bytes.write(tag); 114 } 115 } 116 117 this(BytesIO bytes) { 118 _bytes = bytes; 119 } 120 121 @property BytesIO stream() { return _bytes; } 122 123 static Exception unexpectedTag(char tag, string expectTags = "") { 124 if ((tag != 0) && (expectTags.length != 0)) { 125 return new Exception("Tags '" ~ expectTags ~ "' expected, but '" ~ tag ~ "' found in stream"); 126 } 127 else if (tag != 0) { 128 return new Exception("Unexpected serialize tag '" ~ tag ~ "' in stream"); 129 } 130 else { 131 return new Exception("No byte found in stream"); 132 } 133 } 134 BytesIO readRaw() { 135 BytesIO bytes = new BytesIO(); 136 readRaw(bytes); 137 return bytes; 138 } 139 BytesIO readRaw(BytesIO bytes) { 140 return readRaw(bytes, _bytes.read()); 141 } 142 BytesIO readRaw(BytesIO bytes, char tag) { 143 bytes.write(tag); 144 switch (tag) { 145 case '0': .. case '9': break; 146 case TagNull, TagEmpty, TagTrue, TagFalse, TagNaN: break; 147 case TagInfinity: bytes.write(_bytes.read()); break; 148 case TagInteger, TagLong, TagDouble, TagRef: readNumberRaw(bytes); break; 149 case TagDate, TagTime: readDateTimeRaw(bytes); break; 150 case TagUTF8Char: readUTF8CharRaw(bytes); break; 151 case TagBytes: readBytesRaw(bytes); break; 152 case TagString: readStringRaw(bytes); break; 153 case TagGuid: readGuidRaw(bytes); break; 154 case TagList, TagMap, TagObject: readComplexRaw(bytes); break; 155 case TagClass: readComplexRaw(bytes); readRaw(bytes); break; 156 case TagError: readRaw(bytes); break; 157 default: throw unexpectedTag(tag); 158 } 159 return bytes; 160 } 161 } 162 163 class Reader : RawReader { 164 private { 165 bool _simple; 166 ReaderRefer _refer; 167 Tuple!(TypeInfo, string[], string)[] _classref; 168 169 string _readStringWithoutTag() { 170 string result = _bytes.readString(_bytes.readInt(TagQuote)); 171 _bytes.skip(1); 172 return result; 173 } 174 T readRef(T)() { 175 static if (is(Unqual!T == Variant)) { 176 return cast(T)_refer.read(_bytes.readInt(TagSemicolon)); 177 } 178 else { 179 return cast(T)_refer.read(_bytes.readInt(TagSemicolon)).get!(Unqual!T); 180 } 181 } 182 T readInteger(T)(char tag) if (isIntegral!T) { 183 alias U = Unqual!T; 184 switch(tag) { 185 case '0': .. case '9': return cast(T)(tag - '0'); 186 case TagInteger, TagLong: return readIntegerWithoutTag!T(); 187 case TagDouble: return cast(T)to!U(readDoubleWithoutTag!real()); 188 case TagNull: return cast(T)to!U(0); 189 case TagEmpty: return cast(T)to!U(0); 190 case TagTrue: return cast(T)to!U(1); 191 case TagFalse: return cast(T)to!U(0); 192 case TagUTF8Char: return cast(T)to!U(readUTF8CharWithoutTag!string()); 193 case TagString: return cast(T)to!U(readStringWithoutTag!string()); 194 case TagRef: return cast(T)to!U(readRef!string()); 195 default: throw unexpectedTag(tag); 196 } 197 } 198 T readBigInt(T)(char tag) if (is(Unqual!T == BigInt)) { 199 switch(tag) { 200 case '0': .. case '9': return cast(T)BigInt(tag - '0'); 201 case TagInteger, TagLong: return readBigIntWithoutTag!T(); 202 case TagDouble: return cast(T)BigInt(to!long(readDoubleWithoutTag!real())); 203 case TagNull: return cast(T)BigInt(0); 204 case TagEmpty: return cast(T)BigInt(0); 205 case TagTrue: return cast(T)BigInt(1); 206 case TagFalse: return cast(T)BigInt(0); 207 case TagUTF8Char: return cast(T)BigInt(readUTF8CharWithoutTag!string()); 208 case TagString: return cast(T)BigInt(readStringWithoutTag!string()); 209 case TagRef: return cast(T)BigInt(readRef!string()); 210 default: throw unexpectedTag(tag); 211 } 212 } 213 T readDouble(T)(char tag) if (isFloatingPoint!T) { 214 alias U = Unqual!T; 215 switch(tag) { 216 case '0': .. case '9': return cast(T)to!U(tag - '0'); 217 case TagInteger: return cast(T)readIntegerWithoutTag!int(); 218 case TagLong, TagDouble: return readDoubleWithoutTag!T(); 219 case TagNaN: return cast(T)U.nan; 220 case TagInfinity: return readInfinityWithoutTag!T(); 221 case TagNull: return cast(T)to!U(0); 222 case TagEmpty: return cast(T)to!U(0); 223 case TagTrue: return cast(T)to!U(1); 224 case TagFalse: return cast(T)to!U(0); 225 case TagUTF8Char: return cast(T)to!U(readUTF8CharWithoutTag!string()); 226 case TagString: return cast(T)to!U(readStringWithoutTag!string()); 227 case TagRef: return cast(T)to!U(readRef!string()); 228 default: throw unexpectedTag(tag); 229 } 230 } 231 T readBoolean(T)(char tag) if (isBoolean!T) { 232 switch(tag) { 233 case '0': return cast(T)(false); 234 case '1': .. case '9': return cast(T)(true); 235 case TagInteger: return cast(T)(readIntegerWithoutTag!int() != 0); 236 case TagLong: return cast(T)(readBigIntWithoutTag!BigInt() != BigInt(0)); 237 case TagDouble: return cast(T)(readDoubleWithoutTag!real() != 0); 238 case TagNull: return cast(T)(false); 239 case TagEmpty: return cast(T)(false); 240 case TagTrue: return cast(T)(true); 241 case TagFalse: return cast(T)(false); 242 case TagUTF8Char: return cast(T)(countUntil("\00", readUTF8CharWithoutTag!char()) >= 0); 243 case TagString: { 244 auto v = readStringWithoutTag!string(); 245 return cast(T)(v != null && v != "" && v != "false"); 246 } 247 case TagRef: { 248 auto v = readRef!string(); 249 return cast(T)(v != null && v != "" && v != "false"); 250 } 251 default: throw unexpectedTag(tag); 252 } 253 } 254 T readDateTime(T)(char tag) if (is(Unqual!T == Date) || 255 is(Unqual!T == TimeOfDay) || 256 is(Unqual!T == DateTime) || 257 is(Unqual!T == SysTime)) { 258 switch(tag) { 259 case TagDate: return readDateWithoutTag!T(); 260 case TagTime: return readTimeWithoutTag!T(); 261 case TagRef: return readRef!T(); 262 default: throw unexpectedTag(tag); 263 } 264 } 265 T readUTF8Char(T)(char tag) if (isSomeChar!T) { 266 alias U = Unqual!T; 267 switch(tag) { 268 case '0': .. case '9': return cast(T)(tag - '0'); 269 case TagInteger, TagLong: return cast(T)readIntegerWithoutTag!int(); 270 case TagDouble: return cast(T)to!U(readDoubleWithoutTag!real()); 271 case TagUTF8Char: return readUTF8CharWithoutTag!T(); 272 case TagString: return cast(T)readStringWithoutTag!(U[])()[0]; 273 case TagRef: return cast(T)readRef!(U[])()[0]; 274 default: throw unexpectedTag(tag); 275 } 276 } 277 T readString(T)(char tag) if (isSomeString!T) { 278 alias U = Unqual!T; 279 switch(tag) { 280 case '0': .. case '9': return cast(T)to!U("" ~ cast(char)tag); 281 case TagInteger, TagLong, TagDouble: return cast(T)to!U(cast(string)_bytes.readUntil(TagSemicolon)); 282 case TagNaN: return cast(T)to!U("NAN"); 283 case TagInfinity: return cast(T)to!U(readInfinityWithoutTag!real()); 284 case TagNull: return null; 285 case TagEmpty: return cast(T)to!U(""); 286 case TagTrue: return cast(T)to!U("true"); 287 case TagFalse: return cast(T)to!U("true"); 288 case TagUTF8Char: return readUTF8CharWithoutTag!T(); 289 case TagString: return readStringWithoutTag!T(); 290 case TagRef: return readRef!T(); 291 default: throw unexpectedTag(tag); 292 } 293 } 294 T readUUID(T)(char tag) if (Unqual!T == UUID) { 295 switch(tag) { 296 case TagNull: return UUID.init; 297 case TagEmpty: return UUID.init; 298 case TagBytes: return UUID(readBytesWithoutTag!(ubyte[16])()); 299 case TagGuid: return readUUIDWithoutTag!T(); 300 case TagString: return UUID(readStringWithoutTag!string()); 301 case TagRef: return readRef!T(); 302 default: throw unexpectedTag(tag); 303 } 304 } 305 T readBytes(T)(char tag) if (isArray!T && 306 (is(Unqual!(ForeachType!T) == ubyte) || 307 is(Unqual!(ForeachType!T) == byte))) { 308 switch(tag) { 309 case TagNull: return T.init; 310 case TagEmpty: return T.init; 311 case TagUTF8Char: return cast(T)(readUTF8CharWithoutTag!string()); 312 case TagString: return cast(T)(readStringWithoutTag!string()); 313 case TagBytes: return readBytesWithoutTag!T(); 314 case TagList: return readArrayWithoutTag!T(); 315 case TagRef: return readRef!T(); 316 default: throw unexpectedTag(tag); 317 } 318 } 319 T readArray(T)(char tag) if (isArray!T) { 320 switch(tag) { 321 case TagNull: return null; 322 case TagEmpty: return T.init; 323 case TagList: return readArrayWithoutTag!T(); 324 case TagRef: return readRef!T(); 325 default: throw unexpectedTag(tag); 326 } 327 } 328 T readObjectAsMap(T)() if (isAssociativeArray!T) { 329 auto index = _bytes.readInt!(int)(TagOpenbrace); 330 auto fields = _classref[index][1]; 331 alias KT = Unqual!(KeyType!T); 332 alias VT = Unqual!(ValueType!T); 333 VT[KT] value; 334 setRef(value); 335 foreach(f; fields) { 336 auto k = cast(KT)f; 337 auto v = unserialize!VT(); 338 value[k] = v; 339 } 340 _bytes.skip(1); 341 return cast(T)value; 342 } 343 T readAssociativeArray(T)(char tag) if (isAssociativeArray!T) { 344 switch(tag) { 345 case TagNull: return null; 346 case TagEmpty: return T.init; 347 case TagMap: return readAssociativeArrayWithoutTag!T(); 348 case TagClass: { 349 readClass(); return readAssociativeArray!T(); 350 } 351 case TagObject: return readObjectAsMap!T(); 352 case TagRef: return readRef!T(); 353 default: throw unexpectedTag(tag); 354 } 355 } 356 T readJSONValue(T)(char tag) if (is(Unqual!T == JSONValue)) { 357 switch(tag) { 358 case '0': .. case '9': return cast(T)JSONValue(cast(long)(tag - '0')); 359 case TagInteger: return cast(T)JSONValue(readIntegerWithoutTag!int()); 360 case TagLong: { 361 BigInt bi = readBigIntWithoutTag!BigInt(); 362 if (bi > BigInt(ulong.max) || bi < BigInt(long.min)) { 363 return cast(T)JSONValue(bi.toDecimalString()); 364 } 365 else if (bi > BigInt(long.max)) { 366 return cast(T)JSONValue(bi.toDecimalString().to!ulong()); 367 } 368 else { 369 return cast(T)JSONValue(bi.toLong()); 370 } 371 } 372 case TagDouble: return cast(T)JSONValue(readDoubleWithoutTag!double()); 373 case TagNaN: return cast(T)JSONValue(double.nan); 374 case TagInfinity: return cast(T)JSONValue(readInfinityWithoutTag!double()); 375 case TagNull: return cast(T)JSONValue(null); 376 case TagEmpty: return cast(T)JSONValue(""); 377 case TagTrue: return cast(T)JSONValue(true); 378 case TagFalse: return cast(T)JSONValue(false); 379 case TagUTF8Char: return cast(T)JSONValue(readUTF8CharWithoutTag!string()); 380 case TagString: return cast(T)JSONValue(readStringWithoutTag!string()); 381 case TagDate: return cast(T)JSONValue(readDateWithoutTag!SysTime().toString()); 382 case TagTime: return cast(T)JSONValue(readTimeWithoutTag!TimeOfDay().toString()); 383 case TagGuid: return cast(T)JSONValue(readUUIDWithoutTag!UUID().toString()); 384 case TagList: return cast(T)JSONValue(readArrayWithoutTag!(JSONValue[])()); 385 case TagMap: return cast(T)JSONValue(readAssociativeArrayWithoutTag!(JSONValue[string])()); 386 case TagClass: { 387 readClass(); return cast(T)JSONValue(readAssociativeArray!(JSONValue[string])()); 388 } 389 case TagObject: return cast(T)JSONValue(readObjectAsMap!(JSONValue[string])()); 390 default: throw unexpectedTag(tag); 391 } 392 } 393 T readObjectAsVariant(T)() if (is(Unqual!T == Variant)) { 394 auto index = _bytes.readInt!(int)(TagOpenbrace); 395 TypeInfo t = _classref[index][0]; 396 string[] fields = _classref[index][1]; 397 auto unserializer = ClassManager.getUnserializer(t, this); 398 if (unserializer is null) { 399 throw new Exception("Type " ~ _classref[index][2] ~ " is not registered."); 400 } 401 unserializer.setRef(); 402 foreach(f; fields) unserializer.setField(f); 403 _bytes.skip(1); 404 return cast(T)(unserializer.get()); 405 } 406 T readVariant(T)(char tag) if (is(Unqual!T == Variant)) { 407 switch(tag) { 408 case '0': .. case '9': return cast(T)Variant(cast(int)(tag - '0')); 409 case TagInteger: return cast(T)Variant(readIntegerWithoutTag!int()); 410 case TagLong: return cast(T)Variant(readBigIntWithoutTag!BigInt()); 411 case TagDouble: return cast(T)Variant(readDoubleWithoutTag!double()); 412 case TagNaN: return cast(T)Variant(double.nan); 413 case TagInfinity: return cast(T)Variant(readInfinityWithoutTag!double()); 414 case TagNull: return cast(T)Variant(null); 415 case TagEmpty: return cast(T)Variant(""); 416 case TagTrue: return cast(T)Variant(true); 417 case TagFalse: return cast(T)Variant(false); 418 case TagUTF8Char: return cast(T)Variant(readUTF8CharWithoutTag!string()); 419 case TagString: return cast(T)Variant(readStringWithoutTag!string()); 420 case TagDate: return cast(T)Variant(readDateWithoutTag!SysTime()); 421 case TagTime: return cast(T)Variant(readTimeWithoutTag!TimeOfDay()); 422 case TagGuid: return cast(T)Variant(readUUIDWithoutTag!UUID()); 423 case TagList: return cast(T)Variant(readArrayWithoutTag!(Variant[])()); 424 case TagMap: return cast(T)Variant(readAssociativeArrayWithoutTag!(Variant[Variant])()); 425 case TagClass: { 426 readClass(); return readVariant!T(); 427 } 428 case TagObject: return readObjectAsVariant!T(); 429 case TagRef: return cast(T)readRef!Variant(); 430 default: throw unexpectedTag(tag); 431 } 432 } 433 void readClass() { 434 string classalias = _readStringWithoutTag(); 435 TypeInfo classtype = ClassManager.getClass(classalias); 436 int count = _bytes.readInt(TagOpenbrace); 437 string[] fields; 438 for (int i = 0; i < count; ++i) { 439 fields ~= readString!string(); 440 } 441 _bytes.skip(1); 442 _classref ~= tuple(classtype, fields, classalias); 443 } 444 T readMapAsObject(T)() if (is(T == struct) || is(T == class)) { 445 alias U = Unqual!T; 446 static if (is(U == Object)) { 447 throw new Exception("cannot convert AssociativeArray to std.Object."); 448 } 449 else { 450 auto count = _bytes.readInt!(int)(TagOpenbrace); 451 ClassManager.register!T(U.stringof); 452 auto unserializer = ClassManager.getUnserializer(typeid(U), this); 453 unserializer.setRef(); 454 foreach(int i; 0..count) { 455 auto f = unserialize!(string)(); 456 unserializer.setField(f); 457 } 458 _bytes.skip(1); 459 return cast(T)(unserializer.get().get!U); 460 } 461 } 462 T readObject(T)(char tag) if (is(T == struct) || is(T == class)) { 463 switch(tag) { 464 static if (is(T == class)) { 465 case TagNull: return cast(T)null; 466 } 467 case TagMap: return readMapAsObject!T(); 468 case TagClass: { 469 readClass(); return readObject!T(); 470 } 471 case TagObject: return readObjectWithoutTag!T(); 472 case TagRef: return readRef!T(); 473 default: throw unexpectedTag(tag); 474 } 475 } 476 T unserialize(T)(char tag) if (isSerializable!T) { 477 alias U = Unqual!T; 478 static if (is(U == enum)) { 479 return cast(T)unserialize!(OriginalType!T)(tag); 480 } 481 else static if (isIntegral!T) { 482 return readInteger!T(tag); 483 } 484 else static if (is(U == BigInt)) { 485 return readBigInt!T(tag); 486 } 487 else static if (isFloatingPoint!T) { 488 return readDouble!T(tag); 489 } 490 else static if (isBoolean!T) { 491 return readBoolean!T(tag); 492 } 493 else static if (is(U == Date) || is(U == TimeOfDay) || 494 is(U == DateTime) || is(U == SysTime)) { 495 return readDateTime!T(tag); 496 } 497 else static if (isSomeChar!T) { 498 return readUTF8Char!T(tag); 499 } 500 else static if (isSomeString!T) { 501 return readString!T(tag); 502 } 503 else static if (is(U == UUID)) { 504 return readUUID!T(tag); 505 } 506 else static if (isArray!T) { 507 alias ET = Unqual!(ForeachType!T); 508 static if (is(ET == ubyte) || is(ET == byte)) { 509 return readBytes!T(tag); 510 } 511 else { 512 return readArray!T(tag); 513 } 514 } 515 else static if (isAssociativeArray!T) { 516 return readAssociativeArray!T(tag); 517 } 518 else static if (is(U == JSONValue)) { 519 return readJSONValue!T(tag); 520 } 521 else static if (is(U == Variant)) { 522 return readVariant!T(tag); 523 } 524 else { 525 return readObject!T(tag); 526 } 527 } 528 } 529 package { 530 void setRef(T)(ref T value) { 531 if (_simple) return; 532 _refer.set(Variant(value)); 533 } 534 void setRef(T)(T value) if (is(T == typeof(null))) { 535 if (_simple) return; 536 _refer.set(Variant(null)); 537 } 538 } 539 540 this(BytesIO bytes, bool simple = false) { 541 super(bytes); 542 _simple = simple; 543 if (simple) { 544 _refer = new FakeReaderRefer(); 545 } 546 else { 547 _refer = new RealReaderRefer(); 548 } 549 } 550 void reset() { 551 _classref = null; 552 _refer.reset(); 553 } 554 T unserialize(T)() if (isSerializable!T) { 555 char tag = _bytes.read(); 556 alias U = Unqual!T; 557 static if (isInstanceOf!(Nullable, U)) { 558 if (tag == TagNull) { 559 return T.init; 560 } 561 else { 562 return cast(T)U(unserialize!(typeof(U.init.get()))(tag)); 563 } 564 } 565 else { 566 return unserialize!T(tag); 567 } 568 } 569 void unserialize(T = void)() if (is(T == void)) { 570 unserialize!Variant(tag); 571 } 572 T readIntegerWithoutTag(T)() if (isIntegral!T) { 573 return cast(T)_bytes.readInt!(Unqual!T)(TagSemicolon); 574 } 575 T readInteger(T)() if (isIntegral!T) { 576 return readInteger!T(_bytes.read()); 577 } 578 T readBigIntWithoutTag(T)() if (is(Unqual!T == BigInt)) { 579 return cast(T)BigInt(cast(string)_bytes.readUntil(TagSemicolon)); 580 } 581 T readBigInt(T)() if (is(Unqual!T == BigInt)) { 582 return readBigInt!T(_bytes.read()); 583 } 584 T readDoubleWithoutTag(T)() if (isFloatingPoint!T) { 585 alias U = Unqual!T; 586 return cast(T)to!U(cast(string)_bytes.readUntil(TagSemicolon)); 587 } 588 T readInfinityWithoutTag(T)() if (isFloatingPoint!T) { 589 alias U = Unqual!T; 590 return cast(T)((_bytes.read() == TagNeg) ? -U.infinity : U.infinity); 591 } 592 T readDouble(T)() if (isFloatingPoint!T) { 593 return readDouble!T(_bytes.read()); 594 } 595 T readDateWithoutTag(T)() if (is(Unqual!T == Date) || is(Unqual!T == DateTime) || is(Unqual!T == SysTime)) { 596 int year = to!int(cast(string)_bytes.read(4)); 597 int month = to!int(cast(string)_bytes.read(2)); 598 int day = to!int(cast(string)_bytes.read(2)); 599 static if (is(Unqual!T == Date)) { 600 ubyte tag = _bytes.skipUntil(TagSemicolon, TagUTC); 601 Date result = Date(year, month, day); 602 } 603 else { 604 int hour = 0; 605 int minute = 0; 606 int second = 0; 607 int hnsecs = 0; 608 char tag = _bytes.read(); 609 if (tag == TagTime) { 610 hour = to!int(cast(string)_bytes.read(2)); 611 minute = to!int(cast(string)_bytes.read(2)); 612 second = to!int(cast(string)_bytes.read(2)); 613 tag = _bytes.read(); 614 if (tag == TagPoint) { 615 hnsecs = to!int(cast(string)_bytes.read(3)) * 10000; 616 tag = _bytes.read(); 617 if ((tag >= '0') && (tag <= '9')) { 618 hnsecs += (tag - '0') * 1000 + to!int(cast(string)_bytes.read(2)) * 10; 619 tag = _bytes.read(); 620 if ((tag >= '0') && (tag <= '9')) { 621 hnsecs += (tag - '0'); 622 _bytes.skip(2); 623 tag = _bytes.read(); 624 } 625 } 626 } 627 } 628 static if (is(Unqual!T == DateTime)) { 629 DateTime result = DateTime(year, month, day, hour, minute, second); 630 } 631 else { 632 SysTime result; 633 if (tag == TagUTC) { 634 result = SysTime(DateTime(year, month, day, hour, minute, second), std.datetime.hnsecs(hnsecs), UTC()); 635 } 636 else { 637 result = SysTime(DateTime(year, month, day, hour, minute, second), std.datetime.hnsecs(hnsecs), LocalTime()); 638 } 639 } 640 } 641 setRef(result); 642 return cast(T)result; 643 } 644 T readTimeWithoutTag(T)() if (is(Unqual!T == TimeOfDay) || is(Unqual!T == DateTime) || is(Unqual!T == SysTime)) { 645 int year = 1970; 646 int month = 1; 647 int day = 1; 648 int hour = to!int(cast(string)_bytes.read(2)); 649 int minute = to!int(cast(string)_bytes.read(2)); 650 int second = to!int(cast(string)_bytes.read(2)); 651 int hnsecs = 0; 652 char tag = _bytes.read(); 653 if (tag == TagPoint) { 654 hnsecs = to!int(cast(string)_bytes.read(3)) * 10000; 655 tag = _bytes.read(); 656 if ((tag >= '0') && (tag <= '9')) { 657 hnsecs += (tag - '0') * 1000 + to!int(cast(string)_bytes.read(2)) * 10; 658 tag = _bytes.read(); 659 if ((tag >= '0') && (tag <= '9')) { 660 hnsecs += (tag - '0'); 661 _bytes.skip(2); 662 tag = _bytes.read(); 663 } 664 } 665 } 666 static if (is(Unqual!T == TimeOfDay)) { 667 TimeOfDay result = TimeOfDay(hour, minute, second); 668 } 669 else static if (is(Unqual!T == DateTime)) { 670 DateTime result = DateTime(year, month, day, hour, minute, second); 671 } 672 else { 673 SysTime result; 674 if (tag == TagUTC) { 675 result = SysTime(DateTime(year, month, day, hour, minute, second), std.datetime.hnsecs(hnsecs), UTC()); 676 } 677 else { 678 result = SysTime(DateTime(year, month, day, hour, minute, second), std.datetime.hnsecs(hnsecs), LocalTime()); 679 } 680 } 681 setRef(result); 682 return cast(T)result; 683 } 684 T readDateTime(T)() if (is(Unqual!T == Date) || is(Unqual!T == TimeOfDay) || 685 is(Unqual!T == DateTime) || is(Unqual!T == SysTime)) { 686 return readDateTime!T(_bytes.read()); 687 } 688 T readUTF8CharWithoutTag(T)() if (isSomeChar!T || isSomeString!T) { 689 alias U = Unqual!T; 690 static if (is(U == string)) { 691 return _bytes.readUTF8Char(); 692 } 693 else { 694 string s = _bytes.readUTF8Char(); 695 static if (isSomeChar!T) { 696 foreach(U c; s) return cast(T)c; 697 } 698 else { 699 return cast(T)to!U(s); 700 } 701 } 702 assert(0); 703 } 704 T readUTF8Char(T)() if (isSomeChar!T) { 705 return readUTF8Char!T(_bytes.read()); 706 } 707 T readStringWithoutTag(T)() if (isSomeString!T) { 708 alias U = Unqual!T; 709 static if (is(U == string)) { 710 string value = _readStringWithoutTag(); 711 } 712 else { 713 U value = to!U(_readStringWithoutTag()); 714 } 715 setRef(value); 716 return cast(T)value; 717 } 718 T readString(T)() if (isSomeString!T) { 719 return readString!T(_bytes.read()); 720 } 721 T readUUIDWithoutTag(T)() if (is(Unqual!T == UUID)) { 722 _bytes.skip(1); 723 UUID uuid = UUID(_bytes.read(36)); 724 _bytes.skip(1); 725 setRef(uuid); 726 return cast(T)uuid; 727 } 728 T readUUID(T)() if (is(Unqual!T == UUID)) { 729 return readUUID!T(_bytes.read()); 730 } 731 T readBytesWithoutTag(T)() if (isArray!T && 732 (is(Unqual!(ForeachType!T) == ubyte) || 733 is(Unqual!(ForeachType!T) == byte))) { 734 alias ET = Unqual!(ForeachType!T); 735 int len = _bytes.readInt(TagQuote); 736 ET[] value = cast(ET[])(_bytes.read(len)); 737 _bytes.skip(1); 738 setRef(value); 739 return cast(T)value; 740 } 741 T readBytes(T)() if (isArray!T && 742 (is(Unqual!(ForeachType!T) == ubyte) || 743 is(Unqual!(ForeachType!T) == byte))) { 744 return readBytes!T(_bytes.read()); 745 } 746 T readArrayWithoutTag(T)() if (isArray!T) { 747 int len = _bytes.readInt(TagOpenbrace); 748 alias ET = Unqual!(ForeachType!T); 749 ET[] value = new ET[len]; 750 setRef(value); 751 foreach (int i; 0..len) value[i] = unserialize!ET(); 752 _bytes.skip(1); 753 return cast(T)value; 754 } 755 alias readArrayWithoutTag readListWithoutTag; 756 T readArray(T)() if (isArray!T) { 757 return readArray!T(_bytes.read()); 758 } 759 alias readArray readList; 760 T readAssociativeArrayWithoutTag(T)() if (isAssociativeArray!T) { 761 alias KT = Unqual!(KeyType!T); 762 alias VT = Unqual!(ValueType!T); 763 VT[KT] value; 764 setRef(value); 765 foreach (int i; 0.._bytes.readInt(TagOpenbrace)) { 766 auto k = unserialize!KT(); 767 auto v = unserialize!VT(); 768 value[k] = v; 769 } 770 _bytes.skip(1); 771 return cast(T)value; 772 } 773 alias readAssociativeArrayWithoutTag readMapWithoutTag; 774 T readAssociativeArray(T)() if (isAssociativeArray!T) { 775 return readAssociativeArray!T(_bytes.read()); 776 } 777 alias readAssociativeArray readMap; 778 T readJSONValue(T)() if (is(Unqual!T == JSONValue)) { 779 return readJSONValue!T(_bytes.read()); 780 } 781 T readVariant(T)() if (is(Unqual!T == Variant)) { 782 return readVariant!T(_bytes.read()); 783 } 784 T readObjectWithoutTag(T)() if (is(T == struct) || is(T == class)) { 785 alias U = Unqual!T; 786 auto index = _bytes.readInt!(int)(TagOpenbrace); 787 auto t = _classref[index][0]; 788 auto fields = _classref[index][1]; 789 if (t is null) { 790 static if (!is(U == Object)) { 791 ClassManager.register!T(U.stringof); 792 t = typeid(U); 793 } 794 else { 795 throw new Exception("Type " ~ _classref[index][2] ~ " is not registered."); 796 } 797 } 798 auto unserializer = ClassManager.getUnserializer(t, this); 799 if (t != typeid(U)) { 800 throw new Exception("cannot convert type " ~ t.toString() ~ " to type " ~ fullyQualifiedName!T); 801 } 802 unserializer.setRef(); 803 foreach(f; fields) unserializer.setField(f); 804 _bytes.skip(1); 805 return cast(T)(unserializer.get().get!U()); 806 } 807 T readObject(T)() if (is(T == struct) || is(T == class)) { 808 return readObject!T(_bytes.read()); 809 } 810 void readTupleWithoutTag(T...)(ref T args) { 811 int len = _bytes.readInt(TagOpenbrace); 812 int n = min(len, args.length); 813 setRef(null); 814 static if (args.length > 0) { 815 foreach (i, ref arg; args) { 816 if (i < n) { 817 arg = unserialize!(typeof(arg))(); 818 } 819 } 820 } 821 if (args.length < len) { 822 for (int i = args.length; i < len; ++i) { 823 unserialize!Variant(); 824 } 825 } 826 _bytes.skip(1); 827 } 828 void readTuple(T...)(ref T args) { 829 char tag = _bytes.read(); 830 enforce(tag == TagList, unexpectedTag(tag)); 831 readTupleWithoutTag(args); 832 } 833 } 834 835 unittest { 836 BytesIO bytes = new BytesIO("nnnnnnnnnnnnnnnnnn"); 837 Reader reader = new Reader(bytes); 838 assert(reader.unserialize!byte() == 0); 839 assert(reader.unserialize!short() == 0); 840 assert(reader.unserialize!int() == 0); 841 assert(reader.unserialize!long() == 0); 842 assert(reader.unserialize!(Nullable!char)().isNull()); 843 assert(reader.unserialize!string() == null); 844 assert(reader.unserialize!bool() == false); 845 assert(reader.unserialize!float() == 0.0f); 846 assert(reader.unserialize!double() == 0.0); 847 assert(reader.unserialize!real() == 0.0); 848 assert(reader.unserialize!(Nullable!int)().isNull()); 849 assert(reader.unserialize!(const byte)() == 0); 850 assert(reader.unserialize!(const Nullable!char)().isNull()); 851 assert(reader.unserialize!(const BigInt)() == BigInt(0)); 852 assert(reader.unserialize!(immutable real)() == 0); 853 assert(reader.unserialize!(immutable Nullable!int)().isNull()); 854 assert(reader.unserialize!(int[])() == null); 855 assert(reader.unserialize!(int[string])() == null); 856 } 857 858 unittest { 859 BytesIO bytes = new BytesIO("0000000000000000"); 860 Reader reader = new Reader(bytes); 861 assert(reader.unserialize!byte() == 0); 862 assert(reader.unserialize!short() == 0); 863 assert(reader.unserialize!int() == 0); 864 assert(reader.unserialize!long() == 0); 865 assert(reader.unserialize!char() == 0); 866 assert(reader.unserialize!string() == "0"); 867 assert(reader.unserialize!bool() == false); 868 assert(reader.unserialize!float() == 0.0f); 869 assert(reader.unserialize!double() == 0.0); 870 assert(reader.unserialize!real() == 0.0); 871 assert(reader.unserialize!(Nullable!int)() == 0); 872 assert(reader.unserialize!(const byte)() == 0); 873 assert(reader.unserialize!(const char)() == 0); 874 assert(reader.unserialize!(const BigInt)() == BigInt(0)); 875 assert(reader.unserialize!(immutable real)() == 0); 876 assert(reader.unserialize!(immutable Nullable!int)() == 0); 877 } 878 879 unittest { 880 BytesIO bytes = new BytesIO("1111111111111111"); 881 Reader reader = new Reader(bytes); 882 assert(reader.unserialize!byte() == 1); 883 assert(reader.unserialize!short() == 1); 884 assert(reader.unserialize!int() == 1); 885 assert(reader.unserialize!long() == 1); 886 assert(reader.unserialize!char() == 1); 887 assert(reader.unserialize!string() == "1"); 888 assert(reader.unserialize!bool() == true); 889 assert(reader.unserialize!float() == 1.0f); 890 assert(reader.unserialize!double() == 1.0); 891 assert(reader.unserialize!real() == 1.0); 892 assert(reader.unserialize!(Nullable!int)() == 1); 893 assert(reader.unserialize!(const byte)() == 1); 894 assert(reader.unserialize!(const char)() == 1); 895 assert(reader.unserialize!(const BigInt)() == BigInt(1)); 896 assert(reader.unserialize!(immutable real)() == 1); 897 assert(reader.unserialize!(immutable Nullable!int)() == 1); 898 } 899 900 unittest { 901 BytesIO bytes = new BytesIO("9999999999999999"); 902 Reader reader = new Reader(bytes); 903 assert(reader.unserialize!byte() == 9); 904 assert(reader.unserialize!short() == 9); 905 assert(reader.unserialize!int() == 9); 906 assert(reader.unserialize!long() == 9); 907 assert(reader.unserialize!char() == 9); 908 assert(reader.unserialize!string() == "9"); 909 assert(reader.unserialize!bool() == true); 910 assert(reader.unserialize!float() == 9.0f); 911 assert(reader.unserialize!double() == 9.0); 912 assert(reader.unserialize!real() == 9.0); 913 assert(reader.unserialize!(Nullable!int)() == 9); 914 assert(reader.unserialize!(const byte)() == 9); 915 assert(reader.unserialize!(const char)() == 9); 916 assert(reader.unserialize!(const BigInt)() == BigInt(9)); 917 assert(reader.unserialize!(immutable real)() == 9); 918 assert(reader.unserialize!(immutable Nullable!int)() == 9); 919 } 920 921 unittest { 922 import hprose.io.writer; 923 BytesIO bytes = new BytesIO(); 924 Writer writer = new Writer(bytes); 925 for (int i = 0; i < 16; i++) writer.serialize(-1234567890); 926 Reader reader = new Reader(bytes); 927 assert(reader.unserialize!byte() == cast(byte)-1234567890); 928 assert(reader.unserialize!short() == cast(short)-1234567890); 929 assert(reader.unserialize!int() == -1234567890); 930 assert(reader.unserialize!long() == -1234567890); 931 assert(reader.unserialize!dchar() == -1234567890); 932 assert(reader.unserialize!string() == "-1234567890"); 933 assert(reader.unserialize!bool() == true); 934 auto f = reader.unserialize!float(); 935 assert(f == cast(float)-1234567890); 936 assert(reader.unserialize!double() == -1234567890); 937 assert(reader.unserialize!real() == -1234567890); 938 assert(reader.unserialize!(Nullable!int)() == -1234567890); 939 assert(reader.unserialize!(const uint)() == cast(uint)-1234567890); 940 assert(reader.unserialize!(const ulong)() == cast(ulong)-1234567890); 941 assert(reader.unserialize!(const BigInt)() == BigInt(-1234567890)); 942 assert(reader.unserialize!(immutable real)() == -1234567890); 943 assert(reader.unserialize!(immutable Nullable!int)() == -1234567890); 944 } 945 946 unittest { 947 import hprose.io.writer; 948 BytesIO bytes = new BytesIO(); 949 Writer writer = new Writer(bytes); 950 for (int i = 0; i < 6; i++) writer.serialize(BigInt("1234567890987654321234567890987654321")); 951 Reader reader = new Reader(bytes); 952 assert(reader.unserialize!string() == "1234567890987654321234567890987654321"); 953 assert(reader.unserialize!bool() == true); 954 auto f = reader.unserialize!float(); 955 auto f2 = to!float("1234567890987654321234567890987654321"); 956 assert(f == f2); 957 auto d = reader.unserialize!double(); 958 auto d2 = to!double("1234567890987654321234567890987654321"); 959 assert(d == d2); 960 auto r = reader.unserialize!real(); 961 auto r2 = to!real("1234567890987654321234567890987654321"); 962 assert(r == r2); 963 assert(reader.unserialize!(const BigInt)() == BigInt("1234567890987654321234567890987654321")); 964 } 965 966 unittest { 967 import hprose.io.writer; 968 BytesIO bytes = new BytesIO(); 969 Writer writer = new Writer(bytes); 970 for (int i = 0; i < 6; i++) writer.serialize(-3.1415926); 971 Reader reader = new Reader(bytes); 972 assert(reader.unserialize!byte() == -3); 973 assert(reader.unserialize!int() == -3); 974 assert(reader.unserialize!bool() == true); 975 auto f = reader.unserialize!float(); 976 auto f2 = to!float("-3.1415926"); 977 assert(f == f2); 978 auto d = reader.unserialize!double(); 979 auto d2 = to!double("-3.1415926"); 980 assert(d == d2); 981 auto r = reader.unserialize!real(); 982 auto r2 = to!real("-3.1415926"); 983 assert(r == r2); 984 } 985 986 unittest { 987 import hprose.io.writer; 988 BytesIO bytes = new BytesIO(); 989 Writer writer = new Writer(bytes); 990 for (int i = 0; i < 6; i++) writer.serialize("123"); 991 Reader reader = new Reader(bytes); 992 assert(reader.unserialize!byte() == cast(byte)123); 993 assert(reader.unserialize!int() == 123); 994 assert(reader.unserialize!bool() == true); 995 auto f = reader.unserialize!float(); 996 auto f2 = to!float("123"); 997 assert(f == f2); 998 auto d = reader.unserialize!double(); 999 auto d2 = to!double("123"); 1000 assert(d == d2); 1001 auto r = reader.unserialize!real(); 1002 auto r2 = to!real("123"); 1003 assert(r == r2); 1004 } 1005 1006 unittest { 1007 import hprose.io.writer; 1008 BytesIO bytes = new BytesIO(); 1009 Writer writer = new Writer(bytes); 1010 for (int i = 0; i < 6; i++) writer.serialize([1,2,3,4,5,6,7]); 1011 Reader reader = new Reader(bytes); 1012 assert(reader.unserialize!(byte[])() == cast(byte[])[1,2,3,4,5,6,7]); 1013 assert(reader.unserialize!(ubyte[])() == cast(ubyte[])[1,2,3,4,5,6,7]); 1014 assert(reader.unserialize!(int[])() == [1,2,3,4,5,6,7]); 1015 assert(reader.unserialize!(uint[])() == [1,2,3,4,5,6,7]); 1016 assert(reader.unserialize!(const ulong[])() == cast(const ulong[])[1,2,3,4,5,6,7]); 1017 assert(reader.unserialize!(immutable(double)[])() == cast(immutable(double)[])[1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0]); 1018 } 1019 1020 private { 1021 class MyClass { 1022 int a; 1023 static const byte b; 1024 private int c = 3; 1025 @property { 1026 int x() const { return c; } 1027 int x(int value) { return c = value; } 1028 } 1029 this() { this.a = 1; } 1030 this(int a) { this.a = a; } 1031 void hello() {} 1032 }; 1033 1034 struct MyStruct { 1035 int a; 1036 static const byte b; 1037 int c = 3; 1038 this(int a) { this.a = a; } 1039 void hello() {} 1040 } 1041 } 1042 1043 unittest { 1044 BytesIO bytes = new BytesIO("D19801201T174854.802400;"); 1045 RawReader reader = new RawReader(bytes); 1046 assert(reader.readRaw().toString() == "D19801201T174854.802400;"); 1047 } 1048 1049 unittest { 1050 import hprose.io.writer; 1051 BytesIO bytes = new BytesIO(); 1052 Writer writer = new Writer(bytes); 1053 for (int i = 0; i < 6; i++) writer.serialize(["Jane": 10.0, "Jack":20, "Bob":15]); 1054 writer.serialize(hprose.io.reader.MyStruct(13)); 1055 Reader reader = new Reader(bytes); 1056 assert(reader.unserialize!(int[string])() == ["Jane": 10, "Jack":20, "Bob":15]); 1057 assert(reader.unserialize!(double[string])() == cast(double[string])["Jane": 10, "Jack":20, "Bob":15]); 1058 assert(reader.unserialize!(byte[string])() == cast(byte[string])["Jane": 10, "Jack":20, "Bob":15]); 1059 assert(reader.unserialize!(ubyte[string])() == cast(ubyte[string])["Jane": 10, "Jack":20, "Bob":15]); 1060 assert(reader.unserialize!(const long[string])() == cast(const long[string])["Jane": 10, "Jack":20, "Bob":15]); 1061 assert(reader.unserialize!(immutable ulong[string])() == cast(immutable ulong[string])["Jane": 10, "Jack":20, "Bob":15]); 1062 assert(reader.unserialize!(int[string])() == ["a": 13, "c": 3]); 1063 } 1064 1065 unittest { 1066 int i = 1234567890; 1067 float f = cast(float)i; 1068 assert(f == 1234567890); 1069 BytesIO bytes = new BytesIO("D20141221T120808.342123432;r0;"); 1070 Reader reader = new Reader(bytes); 1071 auto st = reader.unserialize!(SysTime)(); 1072 auto st2 = reader.unserialize!(shared SysTime)(); 1073 assert(st == st2); 1074 bytes.init("i123456789;u111"); 1075 reader.reset(); 1076 assert(reader.unserialize!(const int)() == 123456789); 1077 assert(reader.unserialize!(const double) == 1.0); 1078 assert(reader.unserialize!(int)() == 1); 1079 assert(reader.unserialize!(Nullable!int)() == 1); 1080 } 1081 1082 unittest { 1083 import hprose.io.writer; 1084 import std.math; 1085 BytesIO bytes = new BytesIO(); 1086 Writer writer = new Writer(bytes); 1087 writer.serialize(1); 1088 writer.serialize(long.max); 1089 writer.serialize(ulong.max); 1090 writer.serialize(BigInt("1234567890987654321234567890")); 1091 writer.serialize(PI); 1092 writer.serialize("你"); 1093 writer.serialize("一闪一闪亮晶晶,烧饼油条卷大葱"); 1094 writer.serialize(UUID("21f7f8de-8051-5b89-8680-0195ef798b6a")); 1095 writer.serialize(SysTime(DateTime(2015, 2, 8, 23, 05, 31))); 1096 writer.serialize(TimeOfDay(12, 12, 21)); 1097 writer.serialize(Date(2015, 2, 8)); 1098 writer.serialize(variantArray(1, "Hello", 3.14, Date(2015, 2, 8))); 1099 writer.serialize(["name": JSONValue("张三"), "age": JSONValue(18)]); 1100 // writer.serialize(hprose.io.reader.MyStruct(13)); 1101 Reader reader = new Reader(bytes); 1102 JSONValue jv = reader.unserialize!(JSONValue)(); 1103 assert(jv == JSONValue(1)); 1104 jv = reader.unserialize!(JSONValue)(); 1105 assert(jv == JSONValue(long.max)); 1106 jv = reader.unserialize!(JSONValue)(); 1107 assert(jv == JSONValue(ulong.max)); 1108 jv = reader.unserialize!(JSONValue)(); 1109 assert(jv.str == "1234567890987654321234567890"); 1110 jv = reader.unserialize!(JSONValue)(); 1111 assert(jv == JSONValue(PI)); 1112 jv = reader.unserialize!(JSONValue)(); 1113 assert(jv.str == "你"); 1114 jv = reader.unserialize!(JSONValue)(); 1115 assert(jv.str == "一闪一闪亮晶晶,烧饼油条卷大葱"); 1116 jv = reader.unserialize!(JSONValue)(); 1117 assert(jv.str == "21f7f8de-8051-5b89-8680-0195ef798b6a"); 1118 jv = reader.unserialize!(JSONValue)(); 1119 assert(jv.str == "2015-Feb-08 23:05:31"); 1120 jv = reader.unserialize!(JSONValue)(); 1121 assert(jv.str == "12:12:21"); 1122 jv = reader.readJSONValue!(JSONValue)(); 1123 assert(jv.str == "2015-Feb-08 00:00:00"); 1124 jv = reader.readJSONValue!(JSONValue)(); 1125 assert(jv[0] == JSONValue(1)); 1126 assert(jv[1].str == "Hello"); 1127 assert(jv[2] == JSONValue(3.14)); 1128 assert(jv[3].str == "2015-Feb-08 00:00:00"); 1129 jv = reader.readJSONValue!(JSONValue)(); 1130 assert(jv["name"].str == "张三"); 1131 assert(jv["age"] == JSONValue(18)); 1132 // jv = reader.readJSONValue!(JSONValue)(); 1133 // assert(jv["a"] == JSONValue(13)); 1134 // assert(jv["c"] == JSONValue(3)); 1135 } 1136 1137 unittest { 1138 import hprose.io.writer; 1139 import std.math; 1140 BytesIO bytes = new BytesIO(); 1141 Writer writer = new Writer(bytes); 1142 writer.serialize(1); 1143 writer.serialize(long.max); 1144 writer.serialize(ulong.max); 1145 writer.serialize(BigInt("1234567890987654321234567890")); 1146 writer.serialize(PI); 1147 writer.serialize("你"); 1148 writer.serialize("一闪一闪亮晶晶,烧饼油条卷大葱"); 1149 writer.serialize(UUID("21f7f8de-8051-5b89-8680-0195ef798b6a")); 1150 writer.serialize(SysTime(DateTime(2015, 2, 8, 23, 05, 31))); 1151 writer.serialize(TimeOfDay(12, 12, 21)); 1152 writer.serialize(Date(2015, 2, 8)); 1153 writer.serialize(variantArray(1, "Hello", 3.14, Date(2015, 2, 8))); 1154 // writer.serialize([JSONValue("张三"): "name", JSONValue(18):"age"]); 1155 // writer.serialize(hprose.io.reader.MyStruct(12)); 1156 Reader reader = new Reader(bytes); 1157 Variant v = reader.unserialize!(Variant)(); 1158 assert(v == Variant(1)); 1159 v = reader.unserialize!(Variant)(); 1160 assert(v == Variant(BigInt(long.max))); 1161 v = reader.unserialize!(Variant)(); 1162 assert(v == Variant(BigInt(ulong.max))); 1163 v = reader.unserialize!(Variant)(); 1164 assert(v == Variant(BigInt("1234567890987654321234567890"))); 1165 v = reader.unserialize!(Variant)(); 1166 assert(v == Variant(double(PI))); 1167 v = reader.unserialize!(Variant)(); 1168 assert(v == "你"); 1169 v = reader.unserialize!(Variant)(); 1170 assert(v == "一闪一闪亮晶晶,烧饼油条卷大葱"); 1171 v = reader.unserialize!(Variant)(); 1172 assert(v == UUID("21f7f8de-8051-5b89-8680-0195ef798b6a")); 1173 v = reader.unserialize!(Variant)(); 1174 assert(v == SysTime(DateTime(2015, 2, 8, 23, 05, 31))); 1175 v = reader.unserialize!(Variant)(); 1176 assert(v == TimeOfDay(12, 12, 21)); 1177 v = reader.readVariant!(Variant)(); 1178 assert(v == SysTime(Date(2015, 2, 8))); 1179 v = reader.readVariant!(Variant)(); 1180 assert(v[0] == Variant(1)); 1181 assert(v[1] == "Hello"); 1182 assert(v[2] == Variant(3.14)); 1183 assert(v[3] == SysTime(Date(2015, 2, 8))); 1184 // v = reader.readVariant!(Variant)(); 1185 // assert(v.get!(Variant[Variant])[Variant("张三")] == "name"); 1186 // assert(v.get!(Variant[Variant])[Variant(18)] == "age"); 1187 // v = reader.readVariant!(Variant)(); 1188 // assert(v.get!(hprose.io.reader.MyStruct)() == hprose.io.reader.MyStruct(12)); 1189 } 1190 1191 unittest { 1192 // BytesIO bytes = new BytesIO("c8\"MyStruct\"1{s1\"c\"}o0{5}c7\"MyClass\"1{s1\"x\"}o1{5}m2{s1\"a\"5s1\"x\"2}"); 1193 // Reader reader = new Reader(bytes); 1194 // hprose.io.reader.MyStruct mystruct = reader.unserialize!(hprose.io.reader.MyStruct)(); 1195 // hprose.io.reader.MyClass myclass = reader.unserialize!(hprose.io.reader.MyClass)(); 1196 // assert(mystruct.a == 0); 1197 // assert(mystruct.c == 5); 1198 // assert(myclass.a == 1); 1199 // assert(myclass.x == 5); 1200 // hprose.io.reader.MyClass myclass2 = reader.unserialize!(hprose.io.reader.MyClass)(); 1201 // assert(myclass2.a == 5); 1202 // assert(myclass2.x == 2); 1203 } 1204 1205 unittest { 1206 BytesIO bytes = new BytesIO("a3{1s5\"Hello\"r1;}"); 1207 Reader reader = new Reader(bytes); 1208 Tuple!(int, string, string, int) value; 1209 reader.readTuple(value.expand); 1210 assert(value == tuple(1, "Hello", "Hello", 0)); 1211 } 1212 1213 unittest { 1214 enum Color { 1215 Red, Blue, Green 1216 } 1217 BytesIO bytes = new BytesIO("a3{012}"); 1218 Reader reader = new Reader(bytes); 1219 Tuple!(Color, Color, Color) value; 1220 reader.readTuple(value.expand); 1221 assert(value == tuple(Color.Red, Color.Blue, Color.Green)); 1222 }