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