1 /++ 2 Macros: 3 AlgorithmREF = $(GREF_ALTTEXT mir-algorithm, $(TT $2), $2, mir, $1)$(NBSP) 4 +/ 5 module mir.ion.value; 6 7 import mir.bignum.decimal: Decimal; 8 import mir.ion.exception; 9 import mir.ion.type_code; 10 import mir.lob; 11 import mir.utility: _expect; 12 import std.traits: isMutable, isIntegral, isSigned, isUnsigned, Unsigned, Signed, isFloatingPoint, ParameterTypeTuple; 13 14 public import mir.ion.type_code; 15 public import mir.ion.exception; 16 17 /++ 18 Ion Version Marker 19 +/ 20 struct IonVersionMarker 21 { 22 /// Major Version 23 ubyte major = 1; 24 /// Minor Version 25 ubyte minor = 0; 26 } 27 28 package IonErrorCode parseVersion(ref const(ubyte)[] data, scope ref IonVersionMarker versionMarker) 29 @safe pure nothrow @nogc 30 { 31 version (LDC) pragma(inline, true); 32 if (data.length < 4 || data[0] != 0xE0 || data[3] != 0xEA) 33 return IonErrorCode.cantParseValueStream; 34 versionMarker = IonVersionMarker(data[1], data[2]); 35 data = data[4 .. $]; 36 return IonErrorCode.none; 37 } 38 39 /// Aliases the $(SUBREF type_code, IonTypeCode) to the corresponding Ion Typed Value type. 40 alias IonType(IonTypeCode code : IonTypeCode.null_) = IonNull; 41 /// ditto 42 alias IonType(IonTypeCode code : IonTypeCode.bool_) = bool; 43 /// ditto 44 alias IonType(IonTypeCode code : IonTypeCode.uInt) = IonUInt; 45 /// ditto 46 alias IonType(IonTypeCode code : IonTypeCode.nInt) = IonNInt; 47 /// ditto 48 alias IonType(IonTypeCode code : IonTypeCode.float_) = IonFloat; 49 /// ditto 50 alias IonType(IonTypeCode code : IonTypeCode.decimal) = IonDecimal; 51 /// ditto 52 alias IonType(IonTypeCode code : IonTypeCode.timestamp) = IonTimestamp; 53 /// ditto 54 alias IonType(IonTypeCode code : IonTypeCode.symbol) = IonSymbolID; 55 /// ditto 56 alias IonType(IonTypeCode code : IonTypeCode..string) = const(char)[]; 57 /// ditto 58 alias IonType(IonTypeCode code : IonTypeCode.clob) = Clob; 59 /// ditto 60 alias IonType(IonTypeCode code : IonTypeCode.blob) = Blob; 61 /// ditto 62 alias IonType(IonTypeCode code : IonTypeCode.list) = IonList; 63 /// ditto 64 alias IonType(IonTypeCode code : IonTypeCode.sexp) = IonSexp; 65 /// ditto 66 alias IonType(IonTypeCode code : IonTypeCode.struct_) = IonStruct; 67 /// ditto 68 alias IonType(IonTypeCode code : IonTypeCode.annotations) = IonAnnotationWrapper; 69 70 /// Aliases the type to the corresponding $(SUBREF type_code, IonTypeCode). 71 alias IonTypeCodeOf(T : IonNull) = IonTypeCode.null_; 72 /// ditto 73 alias IonTypeCodeOf(T : bool) = IonTypeCode.bool_; 74 /// ditto 75 alias IonTypeCodeOf(T : IonUInt) = IonTypeCode.uInt; 76 /// ditto 77 alias IonTypeCodeOf(T : IonNInt) = IonTypeCode.nInt; 78 /// ditto 79 alias IonTypeCodeOf(T : IonFloat) = IonTypeCode.float_; 80 /// ditto 81 alias IonTypeCodeOf(T : IonDecimal) = IonTypeCode.decimal; 82 /// ditto 83 alias IonTypeCodeOf(T : IonTimestamp) = IonTypeCode.timestamp; 84 /// ditto 85 alias IonTypeCodeOf(T : IonSymbolID) = IonTypeCode.symbol; 86 /// ditto 87 alias IonTypeCodeOf(T : const(char)[]) = IonTypeCode..string; 88 /// ditto 89 alias IonTypeCodeOf(T : Clob) = IonTypeCode.clob; 90 /// ditto 91 alias IonTypeCodeOf(T : Blob) = IonTypeCode.blob; 92 /// ditto 93 alias IonTypeCodeOf(T : IonList) = IonTypeCode.list; 94 /// ditto 95 alias IonTypeCodeOf(T : IonSexp) = IonTypeCode.sexp; 96 /// ditto 97 alias IonTypeCodeOf(T : IonStruct) = IonTypeCode.struct_; 98 /// ditto 99 alias IonTypeCodeOf(T : IonAnnotationWrapper) = IonTypeCode.annotations; 100 101 /++ 102 A template to check if the type is one of Ion Typed Value types. 103 See_also: $(SUBREF type_code, IonTypeCode) 104 +/ 105 enum isIonType(T) = false; 106 /// ditto 107 enum isIonType(T : IonNull) = true; 108 /// ditto 109 enum isIonType(T : bool) = true; 110 /// ditto 111 enum isIonType(T : IonUInt) = true; 112 /// ditto 113 enum isIonType(T : IonNInt) = true; 114 /// ditto 115 enum isIonType(T : IonFloat) = true; 116 /// ditto 117 enum isIonType(T : IonDecimal) = true; 118 /// ditto 119 enum isIonType(T : IonTimestamp) = true; 120 /// ditto 121 enum isIonType(T : IonSymbolID) = true; 122 /// ditto 123 enum isIonType(T : const(char)[]) = true; 124 /// ditto 125 enum isIonType(T : Clob) = true; 126 /// ditto 127 enum isIonType(T : Blob) = true; 128 /// ditto 129 enum isIonType(T : IonList) = true; 130 /// ditto 131 enum isIonType(T : IonSexp) = true; 132 /// ditto 133 enum isIonType(T : IonStruct) = true; 134 /// ditto 135 enum isIonType(T : IonAnnotationWrapper) = true; 136 137 /// Ion null value. 138 struct IonNull 139 { 140 /// 141 IonTypeCode code; 142 143 /++ 144 Params: 145 serializer = serializer 146 +/ 147 void serialize(S)(scope ref S serializer) scope const 148 { 149 serializer.putNull(code); 150 } 151 152 string toString() @safe pure nothrow @nogc const 153 { 154 return code.nullStringOf; 155 } 156 } 157 158 /++ 159 Ion Value 160 161 The type descriptor octet has two subfields: a four-bit type code T, and a four-bit length L. 162 163 ---------- 164 7 4 3 0 165 +---------+---------+ 166 value | T | L | 167 +---------+---------+======+ 168 : length [VarUInt] : 169 +==========================+ 170 : representation : 171 +==========================+ 172 ---------- 173 +/ 174 struct IonValue 175 { 176 const(ubyte)[] data; 177 178 /++ 179 Describes value (nothrow version). 180 Params: 181 value = (out) $(LREF IonDescribedValue) 182 Returns: $(SUBREF exception, IonErrorCode) 183 +/ 184 deprecated("") 185 IonErrorCode describe()(scope ref IonDescribedValue value) 186 @safe pure nothrow @nogc const 187 { 188 auto d = data[]; 189 if (auto error = parseValue(d, value)) 190 return error; 191 if (_expect(d.length, false)) 192 return IonErrorCode.illegalBinaryData; 193 return IonErrorCode.none; 194 } 195 196 IonDescribedValue describe()(scope out IonErrorCode error) return scope 197 @safe pure nothrow @nogc const 198 { 199 auto d = data[]; 200 auto value = parseValue(d, error); 201 if (error) 202 return IonDescribedValue.init; 203 if (_expect(d.length, false)) 204 { 205 error = IonErrorCode.illegalBinaryData; 206 return IonDescribedValue.init; 207 } 208 return value; 209 } 210 211 version (D_Exceptions) 212 { 213 /++ 214 Describes value. 215 Returns: $(LREF IonDescribedValue) 216 +/ 217 IonDescribedValue describe()() return scope 218 @safe pure @nogc const 219 { 220 IonErrorCode error; 221 auto ret = describe(error); 222 if (error) 223 throw error.ionException; 224 return ret; 225 } 226 } 227 228 /++ 229 Params: 230 serializer = serializer 231 +/ 232 void serialize(S)(scope ref S serializer) scope const 233 { 234 describe.serialize(serializer); 235 } 236 237 /// 238 pure @safe 239 unittest 240 { 241 import mir.ion.stream; 242 import mir.ser.json; 243 assert(IonValueStream([0x11]).serializeJson == "true"); 244 } 245 } 246 247 /// 248 @safe pure 249 version(mir_ion_test) unittest 250 { 251 import mir.lob; 252 import mir.ion.type_code; 253 import mir.ion.value; 254 // null.string 255 assert(IonValue([0x9F]).describe.get!IonNull == IonNull(IonTypeCode.clob)); 256 // empty string 257 assert(IonValue([0x90]).describe.get!Clob.data == ""); 258 259 assert(IonValue([0x95, 0x63, 0x6f, 0x76, 0x69, 0x64]).describe.get!Clob.data == "covid"); 260 } 261 262 /// 263 @safe pure 264 version(mir_ion_test) unittest 265 { 266 import mir.lob; 267 import mir.ion.type_code; 268 import mir.ion.value; 269 // null.string 270 assert(IonValue([0xAF]).describe.get!IonNull == IonNull(IonTypeCode.blob)); 271 // empty string 272 assert(IonValue([0xA0]).describe.get!Blob.data == ""); 273 274 assert(IonValue([0xA5, 0x63, 0x6f, 0x76, 0x69, 0x64]).describe.get!Blob.data == "covid"); 275 } 276 277 278 /++ 279 Ion Type Descriptor 280 +/ 281 struct IonDescriptor 282 { 283 /++ 284 The type descriptor octet has two subfields: a four-bit type code T, and a four-bit length L. 285 +/ 286 this(scope const(ubyte)* reference) 287 @safe pure nothrow @nogc 288 { 289 assert(reference); 290 this(*reference); 291 } 292 293 /// ditto 294 this(ubyte value) 295 @safe pure nothrow @nogc 296 { 297 this.type = cast(IonTypeCode)(value >> 4); 298 assert(type <= IonTypeCode.max); 299 this.L = cast(uint)(value & 0xF); 300 } 301 302 /// T 303 IonTypeCode type; 304 305 /// L 306 uint L; 307 } 308 309 /++ 310 Ion Described Value stores type descriptor and rerpresentation. 311 +/ 312 struct IonDescribedValue 313 { 314 /// Type Descriptor 315 IonDescriptor descriptor; 316 /// Rerpresentation 317 const(ubyte)[] data; 318 319 /++ 320 Returns: true if the value is any Ion `null`. 321 +/ 322 bool opEquals()(typeof(null)) 323 @safe pure nothrow @nogc const 324 { 325 return descriptor.L == 0xF; 326 } 327 328 /++ 329 Returns: true if the values have the same binary representation. 330 +/ 331 bool opEquals()(scope IonDescribedValue rhs) 332 @safe pure nothrow @nogc const 333 { 334 return this.descriptor == rhs.descriptor && this.data == rhs.data; 335 } 336 337 /++ 338 Gets typed value (nothrow version). 339 Params: 340 value = (out) Ion Typed Value 341 Returns: $(SUBREF exception, IonErrorCode) 342 +/ 343 deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 344 IonErrorCode get(T)(scope ref T value) 345 @safe pure nothrow @nogc const 346 if (isIonType!T || is(T == IonInt)) 347 { 348 static if (is(T == IonNull)) 349 { 350 if (_expect(descriptor.L != 0xF, false)) 351 return IonErrorCode.unexpectedIonType; 352 } 353 else 354 static if (is(T == IonInt)) 355 { 356 if (_expect(descriptor.L == 0xF || (descriptor.type | 1) != IonTypeCodeOf!IonNInt, false)) 357 return IonErrorCode.unexpectedIonType; 358 } 359 else 360 { 361 if (_expect(descriptor.L == 0xF || descriptor.type != IonTypeCodeOf!T, false)) 362 return IonErrorCode.unexpectedIonType; 363 } 364 value = trustedGet!T; 365 return IonErrorCode.none; 366 } 367 368 /++ 369 Gets typed value (nothrow version). 370 Params: 371 value = (out) Ion Typed Value 372 Returns: $(SUBREF exception, IonErrorCode) 373 +/ 374 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 375 T get(T)(scope out IonErrorCode error) return scope 376 @safe pure nothrow @nogc const 377 if (isIonType!T || is(T == IonInt)) 378 { 379 380 static if (is(T == IonNull)) 381 { 382 if (_expect(descriptor.L != 0xF, false)) 383 { 384 error = IonErrorCode.unexpectedIonType; 385 return T.init; 386 } 387 return trustedGet!T; 388 } 389 else 390 static if (is(T == IonInt)) 391 { 392 if (_expect(descriptor.L == 0xF || (descriptor.type | 1) != IonTypeCodeOf!IonNInt, false)) 393 { 394 error = IonErrorCode.unexpectedIonType; 395 return T.init; 396 } 397 return trustedGet!T; 398 } 399 else 400 { 401 if (_expect(descriptor.L == 0xF || descriptor.type != IonTypeCodeOf!T, false)) 402 { 403 error = IonErrorCode.unexpectedIonType; 404 return T.init; 405 } 406 407 static if (is(T == IonAnnotationWrapper)) 408 { 409 size_t length; 410 const(ubyte)[] d = data; 411 error = parseVarUInt(d, length); 412 if (error) 413 return T.init; 414 if (_expect(length == 0, false)) 415 { 416 error = IonErrorCode.zeroAnnotations; 417 return T.init; 418 } 419 if (_expect(length >= d.length, false)) 420 { 421 error = IonErrorCode.unexpectedEndOfData; 422 return T.init; 423 } 424 auto idv = IonValue(d[length .. $]).describe(error); 425 if (error) 426 return T.init; 427 if (_expect(idv.descriptor.type == IonTypeCode.annotations, false)) 428 { 429 error = IonErrorCode.nestedAnnotationsNotAllowed; 430 return T.init; 431 } 432 return T(IonAnnotations(d[0 .. length]), idv); 433 } 434 else 435 { 436 return trustedGet!T; 437 } 438 } 439 } 440 441 /++ 442 Gets typed value. 443 Returns: Ion Typed Value 444 +/ 445 T get(T)() return scope 446 @safe pure @nogc const 447 if (isIonType!T || is(T == IonInt)) 448 { 449 static if (is(T == IonAnnotationWrapper)) 450 { 451 IonErrorCode error; 452 auto ret = get!IonAnnotationWrapper(error); 453 if (error) 454 throw error.ionException; 455 return ret; 456 } 457 else 458 static if (is(T == IonNull)) 459 { 460 if (_expect(descriptor.L != 0xF, false)) 461 throw IonErrorCode.unexpectedIonType.ionException; 462 return trustedGet!T; 463 } 464 else 465 static if (is(T == IonInt)) 466 { 467 if (_expect(descriptor.type == IonTypeCode.null_ || (descriptor.type | 1) != IonTypeCodeOf!IonNInt, false)) 468 throw IonErrorCode.unexpectedIonType.ionException; 469 return trustedGet!T; 470 } 471 else 472 { 473 if (_expect(descriptor.type == IonTypeCode.null_ || descriptor.type != IonTypeCodeOf!T, false)) 474 throw IonErrorCode.unexpectedIonType.ionException; 475 return trustedGet!T; 476 } 477 } 478 479 /++ 480 Gets typed value (nothrow internal version). 481 Returns: 482 Ion Typed Value 483 Note: 484 This function doesn't check the encoded value type. 485 +/ 486 T trustedGet(T)() return scope 487 @safe pure nothrow @nogc const 488 if ((isIonType!T || is(T == IonInt)) && !is(T == IonAnnotationWrapper)) 489 { 490 static if (is(T == IonInt)) 491 { 492 assert(descriptor.type == IonTypeCode.null_ || (descriptor.type == IonTypeCodeOf!IonNInt || descriptor.type == IonTypeCodeOf!IonUInt), T.stringof); 493 } 494 else 495 static if (is(T == IonNull)) 496 { 497 assert(descriptor.L == 0xF, T.stringof); 498 } 499 else 500 { 501 assert(descriptor.type == IonTypeCode.null_ || descriptor.type == IonTypeCodeOf!T, T.stringof); 502 } 503 504 static if (is(T == IonNull)) 505 { 506 return T(descriptor.type); 507 } 508 else 509 static if (is(T == bool)) 510 { 511 return descriptor.L & 1; 512 } 513 else 514 static if (is(T == IonStruct)) 515 { 516 return T(descriptor, data); 517 } 518 else 519 static if (is(T == const(char)[])) 520 { 521 return cast(const(char)[])data; 522 } 523 else 524 static if (is(T == Clob)) 525 { 526 return T(cast(const(char)[])data); 527 } 528 else 529 static if (is(T == IonUInt) || is(T == IonNInt) || is(T == IonSymbolID)) 530 { 531 return T(data); 532 } 533 else 534 static if (is(T == IonInt)) 535 { 536 return T(descriptor.type & 1, data); 537 } 538 else 539 { 540 return T(data); 541 } 542 } 543 544 // Issue 21681 workaround 545 private void serializeDummy(S)(scope ref S serializer) scope const @safe 546 { 547 final switch (descriptor.type) with (IonTypeCode) 548 { 549 case IonTypeCode.null_: 550 trustedGet!IonNull.serialize(serializer); 551 break; 552 case IonTypeCode.bool_: 553 serializer.putValue(trustedGet!bool); 554 break; 555 case IonTypeCode.uInt: 556 case IonTypeCode.nInt: 557 trustedGet!IonInt.serialize(serializer); 558 break; 559 case IonTypeCode.float_: 560 trustedGet!IonFloat.serialize(serializer); 561 break; 562 case IonTypeCode.decimal: 563 trustedGet!IonDecimal.serialize(serializer); 564 break; 565 case IonTypeCode.timestamp: 566 trustedGet!IonTimestamp.serialize(serializer); 567 break; 568 case IonTypeCode.symbol: 569 trustedGet!IonSymbolID.serialize(serializer); 570 break; 571 case IonTypeCode..string: 572 serializer.putValue(trustedGet!(const(char)[])); 573 break; 574 case IonTypeCode.clob: 575 serializer.putValue(trustedGet!Clob); 576 break; 577 case IonTypeCode.blob: 578 serializer.putValue(trustedGet!Blob); 579 break; 580 case IonTypeCode.list: 581 break; 582 case IonTypeCode.sexp: 583 break; 584 case IonTypeCode.struct_: 585 break; 586 case IonTypeCode.annotations: 587 break; 588 } 589 } 590 591 // Issue 21681 workaround 592 private void serializeImpl(S)(scope ref S serializer) scope const @safe pure nothrow @nogc 593 { 594 return invokeAssumingAllAttributes(() 595 { 596 if (this == null) 597 { 598 trustedGet!IonNull.serialize(serializer); 599 } 600 else 601 { 602 final switch (descriptor.type) with (IonTypeCode) 603 { 604 case IonTypeCode.null_: 605 assert(0); 606 case IonTypeCode.bool_: 607 serializer.putValue(trustedGet!bool); 608 break; 609 case IonTypeCode.uInt: 610 case IonTypeCode.nInt: 611 trustedGet!IonInt.serialize(serializer); 612 break; 613 case IonTypeCode.float_: 614 trustedGet!IonFloat.serialize(serializer); 615 break; 616 case IonTypeCode.decimal: 617 trustedGet!IonDecimal.serialize(serializer); 618 break; 619 case IonTypeCode.timestamp: 620 trustedGet!IonTimestamp.serialize(serializer); 621 break; 622 case IonTypeCode.symbol: 623 trustedGet!IonSymbolID.serialize(serializer); 624 break; 625 case IonTypeCode..string: 626 serializer.putValue(trustedGet!(const(char)[])); 627 break; 628 case IonTypeCode.clob: 629 serializer.putValue(trustedGet!Clob); 630 break; 631 case IonTypeCode.blob: 632 serializer.putValue(trustedGet!Blob); 633 break; 634 case IonTypeCode.list: 635 trustedGet!IonList.serialize(serializer); 636 break; 637 case IonTypeCode.sexp: 638 trustedGet!IonSexp.serialize(serializer); 639 break; 640 case IonTypeCode.struct_: 641 trustedGet!IonStruct.serialize(serializer); 642 break; 643 case IonTypeCode.annotations: 644 get!IonAnnotationWrapper.serialize(serializer); 645 break; 646 } 647 } 648 }); 649 } 650 651 /++ 652 Params: 653 serializer = serializer 654 +/ 655 void serialize(S)(scope ref S serializer) scope const @safe 656 { 657 // Issue 21681 workaround 658 serializeImpl(serializer); 659 if (false) 660 serializeDummy(serializer); 661 } 662 } 663 664 private auto invokeAssumingAllAttributes(T)(scope T t) @trusted pure nothrow @nogc 665 { 666 import std.traits: functionAttributes, functionLinkage, FunctionAttribute, SetFunctionAttributes; 667 enum attrs = functionAttributes!T & ~FunctionAttribute.system & ~FunctionAttribute.trusted | FunctionAttribute.pure_ | FunctionAttribute.nothrow_ | FunctionAttribute.nogc | FunctionAttribute.safe; 668 return (cast(SetFunctionAttributes!(T, functionLinkage!T, attrs)) t)(); 669 } 670 671 /++ 672 Ion integer field. 673 +/ 674 struct IonIntField 675 { 676 /// 677 const(ubyte)[] data; 678 679 /++ 680 Params: 681 value = (out) signed integer 682 Returns: $(SUBREF exception, IonErrorCode) 683 +/ 684 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 685 IonErrorCode get(T)(scope ref T value) 686 @safe pure nothrow @nogc scope const 687 if (isSigned!T) 688 { 689 auto d = cast()data; 690 size_t i; 691 T f; 692 bool s; 693 if (d.length == 0) 694 goto R; 695 f = d[0] & 0x7F; 696 s = d[0] >> 7; 697 for(;;) 698 { 699 d = d[1 .. $]; 700 if (d.length == 0) 701 { 702 if (f < 0) 703 break; 704 if (s) 705 f = cast(T)(0-f); 706 R: 707 value = f; 708 return IonErrorCode.none; 709 } 710 i += cast(bool)f; 711 f <<= 8; 712 f |= d[0]; 713 if (i >= T.sizeof) 714 break; 715 } 716 return IonErrorCode.overflowInIntegerValue; 717 } 718 719 version (D_Exceptions) 720 { 721 /++ 722 Returns: signed integer 723 Precondition: `this != null`. 724 +/ 725 T get(T)() 726 @safe pure @nogc const 727 if (isSigned!T) 728 { 729 T ret; 730 if (auto error = get(ret)) 731 throw error.ionException; 732 return ret; 733 } 734 } 735 736 /++ 737 Returns: $(SUBREF exception, IonErrorCode) 738 Precondition: `this != null`. 739 +/ 740 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 741 IonErrorCode getErrorCode(T)() 742 @trusted pure nothrow @nogc const 743 if (isSigned!T) 744 { 745 T value; 746 return get!T(value); 747 } 748 } 749 750 /// 751 @safe pure 752 version(mir_ion_test) unittest 753 { 754 assert(IonValue([0x1F]).describe.get!IonNull.code == IonTypeCode.bool_); 755 assert(IonValue([0x10]).describe.get!bool == false); 756 assert(IonValue([0x11]).describe.get!bool == true); 757 } 758 759 /++ 760 Ion non-negative integer number. 761 +/ 762 struct IonUInt 763 { 764 /// 765 const(ubyte)[] data; 766 767 768 // /++ 769 // Returns: true if the integer isn't `null.int` and equals to `rhs`. 770 // +/ 771 // bool opEquals(ulong rhs) 772 // @safe pure nothrow @nogc const 773 // { 774 // return field == rhs; 775 // } 776 777 /++ 778 Params: 779 value = (out) unsigned or signed integer 780 Returns: $(SUBREF exception, IonErrorCode) 781 +/ 782 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 783 IonErrorCode get(T)(scope ref T value) 784 @trusted pure nothrow @nogc scope const 785 if (isIntegral!T && T.sizeof >= 4) 786 { 787 static if (isUnsigned!T) 788 { 789 return data.IonSymbolID.get(value); 790 } 791 else 792 { 793 Unsigned!T uvalue; 794 if (auto error = this.get(uvalue)) 795 return error; 796 value = uvalue; 797 if (_expect(value < 0, false)) 798 return IonErrorCode.overflowInIntegerValue; 799 return IonErrorCode.none; 800 } 801 } 802 803 /// ditto 804 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 805 IonErrorCode get(T)(scope ref T value) 806 @trusted pure nothrow @nogc scope const 807 if (isIntegral!T && T.sizeof < 4) 808 { 809 static if (isUnsigned!T) 810 uint ext; 811 else 812 int ext; 813 if (auto error = this.get(ext)) 814 return error; 815 if (cast(T)ext != ext) 816 return IonErrorCode.overflowInIntegerValue; 817 value = cast(T)ext; 818 return IonErrorCode.none; 819 } 820 821 version (D_Exceptions) 822 { 823 /++ 824 Returns: unsigned or signed integer 825 +/ 826 T get(T)() 827 @safe pure @nogc const 828 if (isIntegral!T) 829 { 830 T ret; 831 if (auto error = get(ret)) 832 throw error.ionException; 833 return ret; 834 } 835 } 836 837 /++ 838 Returns: $(SUBREF exception, IonErrorCode) 839 +/ 840 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 841 IonErrorCode getErrorCode(T)() 842 @trusted pure nothrow @nogc const 843 if (isIntegral!T) 844 { 845 T value; 846 return get!T(value); 847 } 848 } 849 850 /// 851 @safe pure 852 version(mir_ion_test) unittest 853 { 854 import mir.test; 855 assert(IonValue([0x2F]).describe.get!IonNull == IonNull(IonTypeCode.uInt)); 856 assert(IonValue([0x21, 0x07]).describe.get!IonUInt.get!int == 7); 857 858 int v; 859 assert(IonValue([0x22, 0x01, 0x04]).describe.get!IonUInt.get(v) == IonErrorCode.none); 860 v.should == 260; 861 } 862 863 @safe pure 864 version(mir_ion_test) unittest 865 { 866 import mir.test: should; 867 alias AliasSeq(T...) = T; 868 foreach (T; AliasSeq!(byte, short, int, long, ubyte, ushort, uint, ulong)) 869 { 870 IonValue([0x20]).describe.get!IonUInt.getErrorCode!T.should == 0; 871 IonValue([0x21, 0x00]).describe.get!IonUInt.getErrorCode!T.should == 0; 872 873 IonValue([0x21, 0x07]).describe.get!IonUInt.get!T.should == 7; 874 IonValue([0x2E, 0x81, 0x07]).describe.get!IonUInt.get!T.should == 7; 875 IonValue([0x2A, 0,0,0, 0,0,0, 0,0,0, 0x07]).describe.get!IonUInt.get!T.should == 7; 876 } 877 878 IonValue([0x21, 0x7F]).describe.get!IonUInt.get!byte.should == byte.max; 879 IonValue([0x22, 0x7F, 0xFF]).describe.get!IonUInt.get!short.should == short.max; 880 IonValue([0x24, 0x7F, 0xFF,0xFF,0xFF]).describe.get!IonUInt.get!int.should == int.max; 881 IonValue([0x28, 0x7F, 0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF]).describe.get!IonUInt.get!long.should == long.max; 882 IonValue([0x2A, 0,0, 0x7F, 0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF]).describe.get!IonUInt.get!long.should == long.max; 883 884 IonValue([0x21, 0xFF]).describe.get!IonUInt.get!ubyte.should == ubyte.max; 885 IonValue([0x22, 0xFF, 0xFF]).describe.get!IonUInt.get!ushort.should == ushort.max; 886 IonValue([0x24, 0xFF, 0xFF,0xFF,0xFF]).describe.get!IonUInt.get!uint.should == uint.max; 887 IonValue([0x28, 0xFF, 0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF]).describe.get!IonUInt.get!ulong.should == ulong.max; 888 IonValue([0x2A, 0,0, 0xFF, 0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF]).describe.get!IonUInt.get!ulong.should == ulong.max; 889 890 IonValue([0x21, 0x80]).describe.get!IonUInt.getErrorCode!byte.should == IonErrorCode.overflowInIntegerValue; 891 IonValue([0x22, 0x80, 0]).describe.get!IonUInt.getErrorCode!short.should == IonErrorCode.overflowInIntegerValue; 892 IonValue([0x24, 0x80, 0,0,0]).describe.get!IonUInt.getErrorCode!int.should == IonErrorCode.overflowInIntegerValue; 893 894 IonValue([0x22, 1, 0]).describe.get!IonUInt.getErrorCode!ubyte.should == IonErrorCode.overflowInIntegerValue; 895 IonValue([0x23, 1, 0,0]).describe.get!IonUInt.getErrorCode!ushort.should == IonErrorCode.overflowInIntegerValue; 896 IonValue([0x25, 1, 0,0,0,0]).describe.get!IonUInt.getErrorCode!uint.should == IonErrorCode.overflowInIntegerValue; 897 IonValue([0x29, 1, 0,0,0,0,0,0,0,0]).describe.get!IonUInt.getErrorCode!ulong.should == IonErrorCode.overflowInIntegerValue; 898 } 899 900 /++ 901 Ion negative integer number. 902 +/ 903 struct IonNInt 904 { 905 /// 906 const(ubyte)[] data; 907 908 // /++ 909 // Returns: true if the integer isn't `null.int` and equals to `rhs`. 910 // +/ 911 // bool opEquals(long rhs) 912 // @safe pure nothrow @nogc const 913 // { 914 // if (rhs >= 0) 915 // return false; 916 // return IonUInt(data) == -rhs; 917 // } 918 919 /++ 920 Params: 921 value = (out) signed or unsigned integer 922 Returns: $(SUBREF exception, IonErrorCode) 923 +/ 924 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 925 IonErrorCode get(T)(scope ref T value) 926 @trusted pure nothrow @nogc scope const 927 if (isIntegral!T && T.sizeof >= 4) 928 { 929 static if (isUnsigned!T) 930 { 931 return IonErrorCode.overflowInIntegerValue; 932 } 933 else 934 { 935 Unsigned!T uvalue; 936 if (auto overflow = data.IonUInt.get(uvalue)) 937 return IonErrorCode.overflowInIntegerValue; 938 value = -uvalue; 939 if (_expect(value >= 0, false)) 940 return IonErrorCode.overflowInIntegerValue; 941 return IonErrorCode.none; 942 } 943 } 944 945 /// ditto 946 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 947 IonErrorCode get(T)(scope ref T value) 948 @trusted pure nothrow @nogc scope const 949 if (isIntegral!T && T.sizeof < 4) 950 { 951 static if (isUnsigned!T) 952 uint ext; 953 else 954 int ext; 955 if (auto error = this.get(ext)) 956 return error; 957 if (cast(T)ext != ext) 958 return IonErrorCode.overflowInIntegerValue; 959 value = cast(T)ext; 960 return IonErrorCode.none; 961 } 962 963 version (D_Exceptions) 964 { 965 /++ 966 Returns: unsigned or signed integer 967 +/ 968 T get(T)() 969 @safe pure @nogc const 970 if (isIntegral!T) 971 { 972 T ret; 973 if (auto error = get(ret)) 974 throw error.ionException; 975 return ret; 976 } 977 } 978 979 /++ 980 Returns: $(SUBREF exception, IonErrorCode) 981 +/ 982 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 983 IonErrorCode getErrorCode(T)() 984 @trusted pure nothrow @nogc const 985 if (isIntegral!T) 986 { 987 T value; 988 return get!T(value); 989 } 990 } 991 992 /// 993 @safe pure 994 version(mir_ion_test) unittest 995 { 996 import mir.test; 997 assert(IonValue([0x3F]).describe.get!IonNull == IonNull(IonTypeCode.nInt)); 998 assert(IonValue([0x31, 0x07]).describe.get!IonNInt.get!int == -7); 999 1000 long v; 1001 assert(IonValue([0x32, 0x01, 0x04]).describe.get!IonNInt.get(v) == IonErrorCode.none); 1002 v.should == -260; 1003 1004 // IonNInt can't store zero according to the Ion Binary format specification. 1005 IonErrorCode error; 1006 IonValue([0x30]).describe(error); 1007 assert(error == IonErrorCode.negativeIntegerZero); 1008 IonValue([0x31, 0x00]).describe(error); 1009 assert(error == IonErrorCode.negativeIntegerZero); 1010 IonValue([0x3E, 0x80]).describe(error); 1011 assert(error == IonErrorCode.negativeIntegerZero); 1012 } 1013 1014 @safe pure 1015 version(mir_ion_test) unittest 1016 { 1017 alias AliasSeq(T...) = T; 1018 foreach (T; AliasSeq!(byte, short, int, long, ubyte, ushort, uint, ulong)) 1019 { 1020 static if (!__traits(isUnsigned, T)) 1021 { // signed 1022 assert(IonValue([0x31, 0x07]).describe.get!IonNInt.get!T == -7); 1023 assert(IonValue([0x3E, 0x81, 0x07]).describe.get!IonNInt.get!T == -7); 1024 assert(IonValue([0x3A, 0,0,0, 0,0,0, 0,0,0, 0x07]).describe.get!IonNInt.get!T == -7); 1025 } 1026 else 1027 { // unsigned integers can't represent negative numbers 1028 assert(IonValue([0x31, 0x07]).describe.get!IonNInt.getErrorCode!T == IonErrorCode.overflowInIntegerValue); 1029 assert(IonValue([0x3E, 0x81, 0x07]).describe.get!IonNInt.getErrorCode!T == IonErrorCode.overflowInIntegerValue); 1030 assert(IonValue([0x3A, 0,0,0, 0,0,0, 0,0,0, 0x07]).describe.get!IonNInt.getErrorCode!T == IonErrorCode.overflowInIntegerValue); 1031 } 1032 } 1033 1034 assert(IonValue([0x31, 0x80]).describe.get!IonNInt.get!byte == byte.min); 1035 assert(IonValue([0x32, 0x80, 0]).describe.get!IonNInt.get!short == short.min); 1036 assert(IonValue([0x34, 0x80, 0,0,0]).describe.get!IonNInt.get!int == int.min); 1037 assert(IonValue([0x38, 0x80, 0,0,0, 0,0,0,0]).describe.get!IonNInt.get!long == long.min); 1038 1039 assert(IonValue([0x31, 0x81]).describe.get!IonNInt.getErrorCode!byte == IonErrorCode.overflowInIntegerValue); 1040 assert(IonValue([0x32, 0x80, 1]).describe.get!IonNInt.getErrorCode!short == IonErrorCode.overflowInIntegerValue); 1041 assert(IonValue([0x34, 0x80, 0,0,1]).describe.get!IonNInt.getErrorCode!int == IonErrorCode.overflowInIntegerValue); 1042 assert(IonValue([0x38, 0x80, 0,0,0, 0,0,0,1]).describe.get!IonNInt.getErrorCode!long == IonErrorCode.overflowInIntegerValue); 1043 } 1044 1045 /++ 1046 Ion signed integer number. 1047 +/ 1048 struct IonInt 1049 { 1050 /// 1051 bool sign; 1052 /// 1053 const(ubyte)[] data; 1054 1055 /++ 1056 Params: 1057 value = (out) signed or unsigned integer 1058 Returns: $(SUBREF exception, IonErrorCode) 1059 +/ 1060 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1061 IonErrorCode get(T)(scope ref T value) 1062 @trusted pure nothrow @nogc scope const 1063 if (isIntegral!T && T.sizeof >= 4) 1064 { 1065 static if (isUnsigned!T) 1066 { 1067 if (sign) 1068 return IonErrorCode.overflowInIntegerValue; 1069 } 1070 1071 Unsigned!T uvalue; 1072 if (auto overflow = data.IonUInt.get(uvalue)) 1073 return IonErrorCode.overflowInIntegerValue; 1074 value = uvalue; 1075 static if (isSigned!T) 1076 { 1077 if (sign) 1078 { 1079 value = -value; 1080 if (value >= 0) 1081 return IonErrorCode.overflowInIntegerValue; 1082 } 1083 else 1084 { 1085 if (value < 0) 1086 return IonErrorCode.overflowInIntegerValue; 1087 } 1088 } 1089 1090 return IonErrorCode.none; 1091 } 1092 1093 /// ditto 1094 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1095 IonErrorCode get(T)(scope ref T value) 1096 @trusted pure nothrow @nogc scope const 1097 if (isIntegral!T && T.sizeof < 4) 1098 { 1099 static if (isUnsigned!T) 1100 uint ext; 1101 else 1102 int ext; 1103 if (auto error = this.get(ext)) 1104 return error; 1105 if (cast(T)ext != ext) 1106 return IonErrorCode.overflowInIntegerValue; 1107 value = cast(T)ext; 1108 return IonErrorCode.none; 1109 } 1110 1111 version (D_Exceptions) 1112 { 1113 /++ 1114 Returns: unsigned or signed integer 1115 +/ 1116 T get(T)() 1117 @safe pure @nogc const 1118 if (isIntegral!T) 1119 { 1120 T ret; 1121 if (auto error = get(ret)) 1122 throw error.ionException; 1123 return ret; 1124 } 1125 } 1126 1127 /++ 1128 Returns: $(SUBREF exception, IonErrorCode) 1129 +/ 1130 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1131 IonErrorCode getErrorCode(T)() 1132 @trusted pure nothrow @nogc const 1133 if (isIntegral!T) 1134 { 1135 T value; 1136 return get!T(value); 1137 } 1138 1139 /++ 1140 Params: 1141 serializer = serializer 1142 +/ 1143 void serialize(S)(scope ref S serializer) scope const 1144 { 1145 import mir.bignum.integer: BigInt; 1146 auto f = BigInt!128.fromBigEndian(data, sign); 1147 serializer.putValue(f); 1148 } 1149 } 1150 1151 /// test with $(LREF IonUInt)s 1152 @safe pure 1153 version(mir_ion_test) unittest 1154 { 1155 import mir.ion.exception; 1156 import mir.test; 1157 1158 assert(IonValue([0x2F]).describe.get!IonNull == IonNull(IonTypeCode.uInt)); 1159 assert(IonValue([0x21, 0x07]).describe.get!IonInt.get!int == 7); 1160 assert(IonValue([0x20]).describe.get!IonInt.get!int == 0); 1161 1162 int v; 1163 assert(IonValue([0x22, 0x01, 0x04]).describe.get!IonInt.get(v) == IonErrorCode.none); 1164 v.should == 260; 1165 } 1166 1167 /// test with $(LREF IonNInt)s 1168 @safe pure 1169 version(mir_ion_test) unittest 1170 { 1171 import mir.ion.exception; 1172 import mir.test; 1173 1174 assert(IonValue([0x3F]).describe.get!IonNull == IonNull(IonTypeCode.nInt)); 1175 assert(IonValue([0x31, 0x07]).describe.get!IonInt.get!int == -7); 1176 1177 long v; 1178 assert(IonValue([0x32, 0x01, 0x04]).describe.get!IonInt.get(v) == IonErrorCode.none); 1179 v.should == -260; 1180 } 1181 1182 /++ 1183 Ion floating point number. 1184 +/ 1185 struct IonFloat 1186 { 1187 /// 1188 const(ubyte)[] data; 1189 1190 /++ 1191 Params: 1192 value = (out) `float`, `double`, or `real` 1193 Returns: $(SUBREF exception, IonErrorCode) 1194 +/ 1195 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1196 IonErrorCode get(T)(scope ref T value) 1197 @safe pure nothrow @nogc scope const 1198 if (isFloatingPoint!T) 1199 { 1200 if (data.length == 8) 1201 { 1202 value = parseFloating!double(data); 1203 return IonErrorCode.none; 1204 } 1205 if (data.length == 4) 1206 { 1207 value = parseFloating!float(data); 1208 return IonErrorCode.none; 1209 } 1210 if (_expect(data.length, false)) 1211 { 1212 return IonErrorCode.wrongFloatDescriptor; 1213 } 1214 value = 0; 1215 return IonErrorCode.none; 1216 } 1217 1218 version(D_Exceptions) 1219 { 1220 /++ 1221 Returns: floating point number 1222 +/ 1223 T get(T)() 1224 @safe pure @nogc const 1225 if (isFloatingPoint!T) 1226 { 1227 T ret; 1228 if (auto error = get(ret)) 1229 throw error.ionException; 1230 return ret; 1231 } 1232 } 1233 1234 /++ 1235 Returns: $(SUBREF exception, IonErrorCode) 1236 +/ 1237 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1238 IonErrorCode getErrorCode(T)() 1239 @trusted pure nothrow @nogc const 1240 if (isFloatingPoint!T) 1241 { 1242 T value; 1243 return get!T(value); 1244 } 1245 1246 /++ 1247 Params: 1248 serializer = serializer 1249 +/ 1250 void serialize(S)(scope ref S serializer) scope const 1251 { 1252 if (data.length == 8) 1253 { 1254 auto value = parseFloating!double(data); 1255 serializer.putValue(value); 1256 return; 1257 } 1258 if (data.length == 4) 1259 { 1260 auto value = parseFloating!float(data); 1261 serializer.putValue(value); 1262 return; 1263 } 1264 if (_expect(data.length, false)) 1265 { 1266 throw IonErrorCode.wrongFloatDescriptor.ionException; 1267 } 1268 serializer.putValue(0f); 1269 } 1270 } 1271 1272 /// 1273 @safe pure 1274 version(mir_ion_test) unittest 1275 { 1276 // null 1277 assert(IonValue([0x4F]).describe.get!IonNull == IonNull(IonTypeCode.float_)); 1278 1279 // zero 1280 auto ionFloat = IonValue([0x40]).describe.get!IonFloat; 1281 assert(ionFloat.get!float == 0); 1282 assert(ionFloat.get!double == 0); 1283 assert(ionFloat.get!real == 0); 1284 1285 // single 1286 ionFloat = IonValue([0x44, 0x42, 0xAA, 0x40, 0x00]).describe.get!IonFloat; 1287 assert(ionFloat.get!float == 85.125); 1288 assert(ionFloat.get!double == 85.125); 1289 assert(ionFloat.get!real == 85.125); 1290 1291 // double 1292 ionFloat = IonValue([0x48, 0x40, 0x55, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00]).describe.get!IonFloat; 1293 assert(ionFloat.get!float == 85.125); 1294 assert(ionFloat.get!double == 85.125); 1295 assert(ionFloat.get!real == 85.125); 1296 } 1297 1298 /++ 1299 +/ 1300 struct IonDescribedDecimal 1301 { 1302 /// 1303 int exponent; 1304 /// 1305 IonIntField coefficient; 1306 1307 /// 1308 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1309 IonErrorCode get(size_t maxW64bitSize)(scope ref Decimal!maxW64bitSize value) 1310 @safe pure nothrow @nogc scope const 1311 { 1312 enum maxLength = maxW64bitSize * 8; 1313 if (!value.coefficient.copyFromBigEndian(coefficient.data)) 1314 return IonErrorCode.overflowInDecimalValue; 1315 value.exponent = exponent; 1316 if (value.coefficient.length == 0) 1317 return IonErrorCode.none; 1318 value.coefficient.sign = coefficient.data[0] >> 7; 1319 if (value.coefficient.sign) 1320 { 1321 import mir.ndslice.topology: bitwise; 1322 assert(value 1323 .coefficient 1324 .coefficients 1325 .bitwise[coefficient.data.length * 8 - 1]); 1326 value 1327 .coefficient 1328 .coefficients 1329 .bitwise[coefficient.data.length * 8 - 1] = false; 1330 assert(!value 1331 .coefficient 1332 .coefficients 1333 .bitwise[coefficient.data.length * 8 - 1]); 1334 if (value.coefficient.coefficients[$ - 1] == 0) 1335 value.coefficient.length--; 1336 } 1337 return IonErrorCode.none; 1338 } 1339 1340 /++ 1341 Params: 1342 value = (out) floating point number 1343 Returns: $(SUBREF exception, IonErrorCode) 1344 +/ 1345 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1346 IonErrorCode get(T)(scope ref T value) 1347 @safe pure nothrow @nogc scope const 1348 if (isFloatingPoint!T && isMutable!T) 1349 { 1350 Decimal!128 decimal = void; 1351 if (auto ret = this.get(decimal)) 1352 return ret; 1353 value = cast(T) decimal; 1354 return IonErrorCode.none; 1355 } 1356 1357 version(D_Exceptions) 1358 { 1359 /++ 1360 Returns: floating point number 1361 +/ 1362 T get(T = double)() 1363 @safe pure @nogc const 1364 if (isFloatingPoint!T) 1365 { 1366 T ret; 1367 if (auto error = get(ret)) 1368 throw error.ionException; 1369 return ret; 1370 } 1371 } 1372 1373 /++ 1374 Returns: $(SUBREF exception, IonErrorCode) 1375 +/ 1376 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1377 IonErrorCode getErrorCode()() 1378 @trusted pure nothrow @nogc const 1379 if (isFloatingPoint!T) 1380 { 1381 Decimal!128 decimal = void; 1382 return get!T(decimal); 1383 } 1384 1385 /++ 1386 Params: 1387 serializer = serializer 1388 +/ 1389 void serialize(S)(scope ref S serializer) scope const @safe 1390 { 1391 Decimal!128 decimal = void; 1392 if (auto error = this.get(decimal)) 1393 throw error.ionException; 1394 serializer.putValue(decimal); 1395 } 1396 } 1397 1398 /++ 1399 Ion described decimal number. 1400 +/ 1401 struct IonDecimal 1402 { 1403 /// 1404 const(ubyte)[] data; 1405 1406 /++ 1407 Describes decimal (nothrow version). 1408 Params: 1409 value = (out) $(LREF IonDescribedDecimal) 1410 Returns: $(SUBREF exception, IonErrorCode) 1411 +/ 1412 deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1413 IonErrorCode get(T : IonDescribedDecimal)(scope ref T value) 1414 @safe pure nothrow @nogc const 1415 { 1416 const(ubyte)[] d = data; 1417 if (data.length) 1418 { 1419 if (auto error = parseVarInt(d, value.exponent)) 1420 return error; 1421 value.coefficient = IonIntField(d); 1422 } 1423 else 1424 { 1425 value = T.init; 1426 } 1427 return IonErrorCode.none; 1428 } 1429 1430 IonDescribedDecimal get(T : IonDescribedDecimal)(scope out IonErrorCode error) 1431 @safe pure nothrow @nogc const return scope 1432 { 1433 const(ubyte)[] d = data; 1434 if (d.length) 1435 { 1436 IonDescribedDecimal value; 1437 error = parseVarInt(d, value.exponent); 1438 if (error) 1439 return IonDescribedDecimal.init; 1440 value.coefficient = IonIntField(d); 1441 return value; 1442 } 1443 else 1444 { 1445 return IonDescribedDecimal.init; 1446 } 1447 } 1448 1449 /++ 1450 Params: 1451 value = (out) floating point number 1452 Returns: $(SUBREF exception, IonErrorCode) 1453 +/ 1454 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1455 IonErrorCode get(T)(scope ref T value) 1456 @safe pure nothrow @nogc scope const 1457 if (isFloatingPoint!T) 1458 { 1459 IonErrorCode error; 1460 auto decimal = get!IonDescribedDecimal(error); 1461 if (error) 1462 return error; 1463 return decimal.get(value); 1464 } 1465 1466 version (D_Exceptions) 1467 { 1468 /++ 1469 Describes decimal. 1470 Returns: $(LREF IonDescribedDecimal) 1471 +/ 1472 T get(T = IonDescribedDecimal)() return scope 1473 @safe pure @nogc const 1474 { 1475 static if (isFloatingPoint!T) 1476 { 1477 T ret; 1478 if (auto error = get(ret)) 1479 throw error.ionException; 1480 return ret; 1481 } 1482 else 1483 { 1484 IonErrorCode error; 1485 auto ret = get!T(error); 1486 if (error) 1487 throw error.ionException; 1488 return ret; 1489 } 1490 } 1491 } 1492 1493 /++ 1494 Returns: $(SUBREF exception, IonErrorCode) 1495 +/ 1496 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1497 IonErrorCode getErrorCode(T = IonDescribedDecimal)() 1498 @trusted pure nothrow @nogc const 1499 { 1500 T value; 1501 return get!T(value); 1502 } 1503 1504 /++ 1505 Params: 1506 serializer = serializer 1507 +/ 1508 void serialize(S)(scope ref S serializer) scope const @safe 1509 { 1510 this.get!IonDescribedDecimal.serialize(serializer); 1511 } 1512 } 1513 1514 /// 1515 @safe pure 1516 version(mir_ion_test) unittest 1517 { 1518 import mir.test; 1519 // null.decimal 1520 assert(IonValue([0x5F]).describe.get!IonNull == IonNull(IonTypeCode.decimal)); 1521 1522 auto describedDecimal = IonValue([0x56, 0x50, 0xcb, 0x80, 0xbc, 0x2d, 0x86]).describe.get!IonDecimal.get; 1523 assert(describedDecimal.exponent == -2123); 1524 assert(describedDecimal.coefficient.get!int == -12332422); 1525 1526 describedDecimal = IonValue([0x56, 0x00, 0xcb, 0x80, 0xbc, 0x2d, 0x86]).describe.get!IonDecimal.get; 1527 describedDecimal.get!double.should == -12332422e75; 1528 1529 assert(IonValue([0x50]).describe.get!IonDecimal.get!double == 0); 1530 assert(IonValue([0x51, 0x83]).describe.get!IonDecimal.get!double == 0); 1531 assert(IonValue([0x53, 0xc3, 0xb0, 0x39]).describe.get!IonDecimal.get!double == -12.345); 1532 } 1533 1534 /++ 1535 Ion Timestamp 1536 1537 Timestamp representations have 7 components, where 5 of these components are optional depending on the precision of the timestamp. 1538 The 2 non-optional components are offset and year. 1539 The 5 optional components are (from least precise to most precise): `month`, `day`, `hour` and `minute`, `second`, `fraction_exponent` and `fraction_coefficient`. 1540 All of these 7 components are in Universal Coordinated Time (UTC). 1541 +/ 1542 struct IonTimestamp 1543 { 1544 import mir.timestamp; 1545 1546 /// 1547 const(ubyte)[] data; 1548 1549 /++ 1550 Describes decimal (nothrow version). 1551 Params: 1552 value = (out) $(AlgorithmREF timestamp, Timestamp) 1553 Returns: $(SUBREF exception, IonErrorCode) 1554 +/ 1555 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1556 IonErrorCode get(T : Timestamp)(scope ref T value) 1557 @safe pure nothrow @nogc scope const 1558 { 1559 pragma(inline, false); 1560 auto d = data[]; 1561 Timestamp v; 1562 bool offsetSign; 1563 ushort offset; 1564 if (auto error = parseVarInt(d, offset, offsetSign)) 1565 return error; 1566 if (offset || !offsetSign) 1567 v.offset = offsetSign ? cast(short)(0-cast(short)offset) : offset; 1568 ushort year; 1569 if (auto error = parseVarUInt(d, year)) 1570 return error; 1571 v.year = year; 1572 1573 if (d.length == 0) 1574 goto R; 1575 if (auto error = parseVarUInt(d, v.month)) 1576 return error; 1577 v.precision = v.precision.month; 1578 1579 if (d.length == 0) 1580 goto R; 1581 if (auto error = parseVarUInt(d, v.day)) 1582 return error; 1583 v.precision = v.precision.day; 1584 1585 if (d.length == 0) 1586 goto R; 1587 if (auto error = parseVarUInt(d, v.hour)) 1588 return error; 1589 if (v.hour >= 24) 1590 return IonErrorCode.illegalTimeStamp; 1591 { 1592 typeof(v.minute) minute; 1593 if (auto error = parseVarUInt(d, minute)) 1594 return error; 1595 if (v.minute >= 60) 1596 return IonErrorCode.illegalTimeStamp; 1597 v.minute = minute; 1598 } 1599 v.precision = v.precision.minute; 1600 1601 if (d.length == 0) 1602 goto R; 1603 { 1604 typeof(v.second) second; 1605 if (auto error = parseVarUInt(d, second)) 1606 return error; 1607 if (v.second >= 60) 1608 return IonErrorCode.illegalTimeStamp; 1609 v.second = second; 1610 } 1611 v.precision = v.precision.second; 1612 1613 if (d.length == 0) 1614 goto R; 1615 { 1616 typeof(v.fractionExponent) fractionExponent; 1617 long fractionCoefficient; 1618 if (auto error = parseVarInt(d, fractionExponent)) 1619 return error; 1620 if (auto error = IonIntField(d).get(fractionCoefficient)) 1621 return error; 1622 if (fractionCoefficient == 0 && fractionExponent >= 0) 1623 goto R; 1624 static immutable exps = [ 1625 1L, 1626 10L, 1627 100L, 1628 1_000L, 1629 10_000L, 1630 100_000L, 1631 1_000_000L, 1632 10_000_000L, 1633 100_000_000L, 1634 1_000_000_000L, 1635 10_000_000_000L, 1636 100_000_000_000L, 1637 1_000_000_000_000L, 1638 ]; 1639 if (fractionExponent < -12 1640 || fractionExponent > 0 1641 || fractionCoefficient < 0 1642 || fractionCoefficient >= exps[0-fractionExponent]) 1643 return IonErrorCode.illegalTimeStamp; 1644 v.fractionExponent = fractionExponent; 1645 v.fractionCoefficient = fractionCoefficient; 1646 } 1647 v.precision = v.precision.fraction; 1648 R: 1649 import mir.date: maxDay; 1650 1651 // duration 1652 if (v.day == 88 || v.day == 99) 1653 { 1654 } 1655 else 1656 // time of day 1657 if (v.precision > v.Precision.day && v.day == 0) 1658 { 1659 if (v.year || v.month) 1660 return IonErrorCode.illegalTimeStamp; 1661 } 1662 else 1663 if (!v.year) 1664 { 1665 return IonErrorCode.illegalTimeStamp; 1666 } 1667 else 1668 if (v.precision >= Timestamp.Precision.month) 1669 { 1670 if (v.month == 0 || v.month > 12) 1671 return IonErrorCode.illegalTimeStamp; 1672 if (v.precision > Timestamp.Precision.month && (v.day == 0 || v.day > maxDay(v.year, v.month))) 1673 return IonErrorCode.illegalTimeStamp; 1674 } 1675 1676 value = v; 1677 return IonErrorCode.none; 1678 } 1679 1680 version (D_Exceptions) 1681 { 1682 /++ 1683 Describes decimal. 1684 Returns: $(LREF Timestamp) 1685 +/ 1686 Timestamp get(T = Timestamp)() 1687 @safe pure @nogc const 1688 { 1689 T ret; 1690 if (auto error = get(ret)) 1691 throw error.ionException; 1692 return ret; 1693 } 1694 } 1695 1696 /++ 1697 Returns: $(SUBREF exception, IonErrorCode) 1698 +/ 1699 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1700 IonErrorCode getErrorCode(T = Timestamp)() 1701 @trusted pure nothrow @nogc const 1702 { 1703 T value; 1704 return get!T(value); 1705 } 1706 1707 /++ 1708 Params: 1709 serializer = serializer 1710 +/ 1711 void serialize(S)(scope ref S serializer) scope const 1712 { 1713 serializer.putValue(this.get!Timestamp); 1714 } 1715 } 1716 1717 /// 1718 @safe pure 1719 version(mir_ion_test) unittest 1720 { 1721 import mir.timestamp; 1722 1723 // null.timestamp 1724 assert(IonValue([0x6F]).describe.get!IonNull == IonNull(IonTypeCode.timestamp)); 1725 1726 ubyte[][] set = [ 1727 [0x68, 0x80, 0x0F, 0xD0, 0x87, 0x88, 0x82, 0x83, 0x84, ], // 2000-07-08T02:03:04Z with no fractional seconds 1728 [0x69, 0x80, 0x0F, 0xD0, 0x87, 0x88, 0x82, 0x83, 0x84, 0x80, ], // The same instant with 0d0 fractional seconds and implicit zero coefficient 1729 [0x6A, 0x80, 0x0F, 0xD0, 0x87, 0x88, 0x82, 0x83, 0x84, 0x80, 00], // The same instant with 0d0 fractional seconds and explicit zero coefficient 1730 [0x69, 0x80, 0x0F, 0xD0, 0x87, 0x88, 0x82, 0x83, 0x84, 0xC0, ], // The same instant with 0d-0 fractional seconds 1731 [0x69, 0x80, 0x0F, 0xD0, 0x87, 0x88, 0x82, 0x83, 0x84, 0x81, ], // The same instant with 0d1 fractional seconds 1732 ]; 1733 1734 auto r = Timestamp(2000, 7, 8, 2, 3, 4).withOffset(0); 1735 1736 foreach(data; set) 1737 { 1738 assert(IonValue(data).describe.get!IonTimestamp.get == r); 1739 } 1740 1741 assert(IonValue([0x69, 0x80, 0x0F, 0xD0, 0x87, 0x88, 0x82, 0x83, 0x84, 0xC2]) 1742 .describe 1743 .get!IonTimestamp 1744 .get == 1745 Timestamp(2000, 7, 8, 2, 3, 4, -2, 0).withOffset(0)); 1746 1747 assert(IonValue([0x6A, 0x80, 0x0F, 0xD0, 0x87, 0x88, 0x82, 0x83, 0x84, 0xC3, 0x10]) 1748 .describe 1749 .get!IonTimestamp 1750 .get == 1751 Timestamp(2000, 7, 8, 2, 3, 4, -3, 16).withOffset(0)); 1752 } 1753 1754 /++ 1755 Ion Symbol Id 1756 1757 In the binary encoding, all Ion symbols are stored as integer symbol IDs whose text values are provided by a symbol table. 1758 If L is zero then the symbol ID is zero and the length and symbol ID fields are omitted. 1759 +/ 1760 struct IonSymbolID 1761 { 1762 /// 1763 const(ubyte)[] data; 1764 1765 /++ 1766 Params: 1767 value = (out) symbol id 1768 Returns: $(SUBREF exception, IonErrorCode) 1769 +/ 1770 1771 // IonErrorCode get(T)(scope ref T value) 1772 // @trusted pure nothrow @nogc const 1773 // if (isUnsigned!T) 1774 // { 1775 // pragma(inline, true); 1776 1777 // auto d = data[]; 1778 1779 // value = 0; 1780 // while (d.length) 1781 // { 1782 // enum c = T.max >> 8; 1783 // if (value > c) 1784 // return IonErrorCode.overflowInIntegerValue; 1785 // value <<= 8; 1786 // value |= d[0]; 1787 // d = d[1 .. $]; 1788 // } 1789 // return IonErrorCode.none; 1790 // } 1791 1792 IonErrorCode get(T)(scope ref T value) 1793 @safe pure nothrow @nogc scope const 1794 if (isUnsigned!T && T.sizeof >= 4) 1795 { 1796 auto d = data[]; 1797 1798 while (_expect(d.length && d[0] == 0, false)) 1799 d = d[1 .. $]; 1800 1801 if (_expect(d.length > value.sizeof, false)) 1802 return IonErrorCode.overflowInIntegerValue; 1803 1804 value = 0; 1805 1806 while (d.length) 1807 { 1808 value <<= 8; 1809 value |= d[0]; 1810 d = d[1 .. $]; 1811 } 1812 1813 return IonErrorCode.none; 1814 } 1815 1816 /// ditto 1817 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1818 IonErrorCode get(T)(scope ref T value) 1819 @trusted pure nothrow @nogc scope const 1820 if (isUnsigned!T && T.sizeof < 4) 1821 { 1822 uint ext; 1823 if (auto error = this.get(ext)) 1824 return error; 1825 if (cast(T)ext != ext) 1826 return IonErrorCode.overflowInIntegerValue; 1827 value = cast(T)ext; 1828 return IonErrorCode.none; 1829 } 1830 1831 /++ 1832 Returns: unsigned or signed integer 1833 +/ 1834 T get(T = size_t)() 1835 @safe pure @nogc const 1836 if (isUnsigned!T) 1837 { 1838 T ret; 1839 if (auto error = get(ret)) 1840 throw error.ionException; 1841 return ret; 1842 } 1843 1844 /++ 1845 Returns: $(SUBREF exception, IonErrorCode) 1846 +/ 1847 // deprecated("Use inout(T) get(T)(scope out IonErrorCode)") 1848 IonErrorCode getErrorCode(T = size_t)() 1849 @trusted pure nothrow @nogc const 1850 if (isUnsigned!T) 1851 { 1852 T value; 1853 return get!T(value); 1854 } 1855 1856 /++ 1857 Serializes SymbolId as Ion value. 1858 Note: This serialization shouldn't be used for `struct` keys or `annotation` list. 1859 Params: 1860 serializer = serializer with `putSymbolId` primitive. 1861 +/ 1862 void serialize(S)(scope ref S serializer) scope const 1863 { 1864 size_t id; 1865 if (auto err = get(id)) 1866 throw err.ionException; 1867 serializer.putSymbolId(id); 1868 } 1869 } 1870 1871 /// 1872 @safe pure 1873 version(mir_ion_test) unittest 1874 { 1875 import mir.test; 1876 assert(IonValue([0x7F]).describe.get!IonNull == IonNull(IonTypeCode.symbol)); 1877 assert(IonValue([0x71, 0x07]).describe.get!IonSymbolID.get == 7); 1878 1879 size_t v; 1880 assert(IonValue([0x72, 0x01, 0x04]).describe.get!IonSymbolID.get(v) == IonErrorCode.none); 1881 v.should == 260; 1882 } 1883 1884 @safe pure 1885 version(mir_ion_test) unittest 1886 { 1887 assert(IonValue([0x70]).describe.get!IonSymbolID.getErrorCode == 0); 1888 assert(IonValue([0x71, 0x00]).describe.get!IonSymbolID.getErrorCode == 0); 1889 1890 assert(IonValue([0x71, 0x07]).describe.get!IonSymbolID.get == 7); 1891 assert(IonValue([0x7E, 0x81, 0x07]).describe.get!IonSymbolID.get == 7); 1892 assert(IonValue([0x7A, 0,0,0, 0,0,0, 0,0,0, 0x07]).describe.get!IonSymbolID.get == 7); 1893 1894 assert(IonValue([0x71, 0xFF]).describe.get!IonSymbolID.get!ubyte == ubyte.max); 1895 assert(IonValue([0x72, 0xFF, 0xFF]).describe.get!IonSymbolID.get!ushort == ushort.max); 1896 assert(IonValue([0x74, 0xFF, 0xFF,0xFF,0xFF]).describe.get!IonSymbolID.get!uint == uint.max); 1897 assert(IonValue([0x78, 0xFF, 0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF]).describe.get!IonSymbolID.get!ulong == ulong.max); 1898 assert(IonValue([0x7A, 0,0, 0xFF, 0xFF,0xFF,0xFF, 0xFF,0xFF,0xFF,0xFF]).describe.get!IonSymbolID.get!ulong == ulong.max); 1899 1900 assert(IonValue([0x72, 1, 0]).describe.get!IonSymbolID.getErrorCode!ubyte == IonErrorCode.overflowInIntegerValue); 1901 assert(IonValue([0x73, 1, 0,0]).describe.get!IonSymbolID.getErrorCode!ushort == IonErrorCode.overflowInIntegerValue); 1902 assert(IonValue([0x75, 1, 0,0,0,0]).describe.get!IonSymbolID.getErrorCode!uint == IonErrorCode.overflowInIntegerValue); 1903 assert(IonValue([0x79, 1, 0,0,0,0,0,0,0,0]).describe.get!IonSymbolID.getErrorCode!ulong == IonErrorCode.overflowInIntegerValue); 1904 } 1905 1906 1907 /// 1908 @safe pure 1909 version(mir_ion_test) unittest 1910 { 1911 // null.string 1912 assert(IonValue([0x8F]).describe.get!IonNull == IonNull(IonTypeCode..string)); 1913 // empty string 1914 assert(IonValue([0x80]).describe.get!(const(char)[]) !is null); 1915 assert(IonValue([0x80]).describe.get!(const(char)[]) == ""); 1916 1917 assert(IonValue([0x85, 0x63, 0x6f, 0x76, 0x69, 0x64]).describe.get!(const(char)[]) == "covid"); 1918 } 1919 1920 /++ 1921 Ion List (array) 1922 +/ 1923 struct IonList 1924 { 1925 /// 1926 const(ubyte)[] data; 1927 private alias DG = int delegate(IonErrorCode error, scope IonDescribedValue value) @safe pure nothrow @nogc; 1928 private alias EDG = int delegate(scope IonDescribedValue value) @safe pure @nogc; 1929 1930 /++ 1931 Returns: true if the sexp is `null.sexp`, `null`, or `()`. 1932 Note: a NOP padding makes in the struct non-empty. 1933 +/ 1934 bool empty() 1935 scope @safe pure nothrow @nogc const @property 1936 { 1937 return data.length == 0; 1938 } 1939 1940 const: 1941 1942 version (D_Exceptions) 1943 { 1944 /++ 1945 +/ 1946 @safe pure @nogc 1947 scope int opApply(scope int delegate(scope IonDescribedValue value) @safe pure @nogc dg) 1948 { 1949 return opApply((IonErrorCode error, scope IonDescribedValue value) { 1950 if (_expect(error, false)) 1951 throw error.ionException; 1952 return dg(value); 1953 }); 1954 } 1955 1956 /// ditto 1957 @trusted @nogc 1958 scope int opApply(scope int delegate(scope IonDescribedValue value) 1959 @safe @nogc dg) { return opApply(cast(EDG) dg); } 1960 1961 /// ditto 1962 @trusted pure 1963 scope int opApply(scope int delegate(scope IonDescribedValue value) 1964 @safe pure dg) { return opApply(cast(EDG) dg); } 1965 1966 /// ditto 1967 @trusted 1968 scope int opApply(scope int delegate(scope IonDescribedValue value) 1969 @safe dg) { return opApply(cast(EDG) dg); } 1970 1971 /// ditto 1972 @system pure @nogc 1973 scope int opApply(scope int delegate(scope IonDescribedValue value) 1974 @system pure @nogc dg) { return opApply(cast(EDG) dg); } 1975 1976 /// ditto 1977 @system @nogc 1978 scope int opApply(scope int delegate(scope IonDescribedValue value) 1979 @system @nogc dg) { return opApply(cast(EDG) dg); } 1980 1981 /// ditto 1982 @system pure 1983 scope int opApply(scope int delegate(scope IonDescribedValue value) 1984 @system pure dg) { return opApply(cast(EDG) dg); } 1985 1986 /// ditto 1987 @system 1988 scope int opApply(scope int delegate(scope IonDescribedValue value) 1989 @system dg) { return opApply(cast(EDG) dg); } 1990 } 1991 1992 /++ 1993 +/ 1994 @safe pure nothrow @nogc 1995 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) @safe pure nothrow @nogc dg) 1996 { 1997 auto d = data[]; 1998 while (d.length) 1999 { 2000 IonErrorCode error; 2001 auto describedValue = parseValue(d, error); 2002 if (error == IonErrorCode.nop) 2003 continue; 2004 if (auto ret = dg(error, describedValue)) 2005 return ret; 2006 assert(!error, "User provided delegate MUST break the iteration when error has non-zero value."); 2007 } 2008 return 0; 2009 } 2010 2011 /// ditto 2012 @trusted nothrow @nogc 2013 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2014 @safe nothrow @nogc dg) { return opApply(cast(DG) dg); } 2015 2016 /// ditto 2017 @trusted pure @nogc 2018 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2019 @safe pure @nogc dg) { return opApply(cast(DG) dg); } 2020 2021 /// ditto 2022 @trusted pure nothrow 2023 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2024 @safe pure nothrow dg) { return opApply(cast(DG) dg); } 2025 2026 /// ditto 2027 @trusted @nogc 2028 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2029 @safe @nogc dg) { return opApply(cast(DG) dg); } 2030 2031 /// ditto 2032 @trusted pure 2033 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2034 @safe pure dg) { return opApply(cast(DG) dg); } 2035 2036 /// ditto 2037 @trusted nothrow 2038 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2039 @safe nothrow dg) { return opApply(cast(DG) dg); } 2040 2041 /// ditto 2042 @trusted 2043 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2044 @safe dg) { return opApply(cast(DG) dg); } 2045 2046 /// ditto 2047 @system pure nothrow @nogc 2048 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2049 @system pure nothrow @nogc dg) { return opApply(cast(DG) dg); } 2050 2051 /// ditto 2052 @system nothrow @nogc 2053 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2054 @system nothrow @nogc dg) { return opApply(cast(DG) dg); } 2055 2056 /// ditto 2057 @system pure @nogc 2058 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2059 @system pure @nogc dg) { return opApply(cast(DG) dg); } 2060 2061 /// ditto 2062 @system pure nothrow 2063 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2064 @system pure nothrow dg) { return opApply(cast(DG) dg); } 2065 2066 /// ditto 2067 @system @nogc 2068 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2069 @system @nogc dg) { return opApply(cast(DG) dg); } 2070 2071 /// ditto 2072 @system pure 2073 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2074 @system pure dg) { return opApply(cast(DG) dg); } 2075 2076 /// ditto 2077 @system nothrow 2078 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2079 @system nothrow dg) { return opApply(cast(DG) dg); } 2080 2081 /// ditto 2082 @system 2083 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2084 @system dg) { return opApply(cast(DG) dg); } 2085 2086 /++ 2087 For iteration with $(LREF IonDescribedValue) elements. 2088 Throws: `IonException` 2089 +/ 2090 version(GenericOpApply) 2091 scope int opApply(Dg)(scope Dg dg) 2092 if (ParameterTypeTuple!Dg.length == 1) 2093 { 2094 foreach (IonErrorCode error, scope IonDescribedValue value; this) 2095 { 2096 if (_expect(error, false)) 2097 throw error.ionException; 2098 if (auto ret = dg(value)) 2099 return ret; 2100 } 2101 return 0; 2102 } 2103 2104 /++ 2105 For iteration with `IonErrorCode` and $(LREF IonDescribedValue) pairs. 2106 +/ 2107 version(GenericOpApply) 2108 scope int opApply(Dg)(scope Dg dg) 2109 if (ParameterTypeTuple!Dg.length == 2) 2110 { 2111 version(LDC) 2112 pragma(inline, true); 2113 pragma (msg, ParameterTypeTuple!Dg); // foreach with 2 parameters 2114 auto d = data[]; 2115 while (d.length) 2116 { 2117 IonDescribedValue describedValue; 2118 auto error = parseValue(d, describedValue); 2119 if (error == IonErrorCode.nop) 2120 continue; 2121 if (auto ret = dg(error, describedValue)) 2122 return ret; 2123 assert(!error, "User provided delegate MUST break the iteration when error has non-zero value."); 2124 } 2125 return 0; 2126 } 2127 2128 /++ 2129 Params: 2130 serializer = serializer 2131 +/ 2132 void serialize(S)(scope ref S serializer) scope const 2133 { 2134 import mir.ser: beginList; 2135 auto state = serializer.beginList(this); 2136 foreach (scope IonDescribedValue value; this) 2137 { 2138 serializer.elemBegin; 2139 value.serializeImpl(serializer); 2140 if (false) 2141 value.serializeDummy(serializer); 2142 } 2143 serializer.listEnd(state); 2144 } 2145 2146 /// 2147 size_t walkLength() scope const @property @safe pure @nogc 2148 { 2149 size_t length; 2150 IonErrorCode firstError; 2151 foreach (IonErrorCode error, scope IonDescribedValue value; this) 2152 { 2153 length++; 2154 if (error) 2155 { 2156 firstError = error; 2157 break; 2158 } 2159 } 2160 if (firstError) 2161 throw firstError.ionException; 2162 return length; 2163 } 2164 } 2165 2166 /// 2167 version(mir_ion_test) unittest 2168 { 2169 // check parsing with NOP padding: 2170 // [NOP, int, NOP, double, NOP] 2171 auto list = IonValue([0xbe, 0x91, 0x00, 0x00, 0x21, 0x0c, 0x00, 0x00, 0x48, 0x43, 0x0c, 0x6b, 0xf5, 0x26, 0x34, 0x00, 0x00, 0x00, 0x00]) 2172 .describe.get!IonList; 2173 size_t i; 2174 foreach (elem; list) 2175 { 2176 if (i == 0) 2177 assert(elem.get!IonUInt.get!int == 12); 2178 if (i == 1) 2179 assert(elem.get!IonFloat.get!double == 100e13); 2180 i++; 2181 } 2182 assert(i == 2); 2183 } 2184 2185 /++ 2186 Ion Sexp (symbol expression, array) 2187 +/ 2188 struct IonSexp 2189 { 2190 /// data view. 2191 const(ubyte)[] data; 2192 2193 private alias DG = IonList.DG; 2194 private alias EDG = IonList.EDG; 2195 2196 /++ 2197 Returns: true if the sexp is `null.sexp`, `null`, or `()`. 2198 Note: a NOP padding makes in the struct makes it non-empty. 2199 +/ 2200 bool empty() 2201 scope @safe pure nothrow @nogc const @property 2202 { 2203 return data.length == 0; 2204 } 2205 2206 const: 2207 2208 version (D_Exceptions) 2209 { 2210 /++ 2211 +/ 2212 @safe pure @nogc 2213 scope int opApply(scope int delegate(scope IonDescribedValue value) @safe pure @nogc dg) 2214 { 2215 return IonList(data).opApply(dg); 2216 } 2217 2218 /// ditto 2219 @trusted @nogc 2220 scope int opApply(scope int delegate(scope IonDescribedValue value) 2221 @safe @nogc dg) { return opApply(cast(EDG) dg); } 2222 2223 /// ditto 2224 @trusted pure 2225 scope int opApply(scope int delegate(scope IonDescribedValue value) 2226 @safe pure dg) { return opApply(cast(EDG) dg); } 2227 2228 /// ditto 2229 @trusted 2230 scope int opApply(scope int delegate(scope IonDescribedValue value) 2231 @safe dg) { return opApply(cast(EDG) dg); } 2232 2233 /// ditto 2234 @system pure @nogc 2235 scope int opApply(scope int delegate(scope IonDescribedValue value) 2236 @system pure @nogc dg) { return opApply(cast(EDG) dg); } 2237 2238 /// ditto 2239 @system @nogc 2240 scope int opApply(scope int delegate(scope IonDescribedValue value) 2241 @system @nogc dg) { return opApply(cast(EDG) dg); } 2242 2243 /// ditto 2244 @system pure 2245 scope int opApply(scope int delegate(scope IonDescribedValue value) 2246 @system pure dg) { return opApply(cast(EDG) dg); } 2247 2248 /// ditto 2249 @system 2250 scope int opApply(scope int delegate(scope IonDescribedValue value) 2251 @system dg) { return opApply(cast(EDG) dg); } 2252 } 2253 2254 /++ 2255 +/ 2256 @safe pure nothrow @nogc 2257 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) @safe pure nothrow @nogc dg) 2258 { 2259 return IonList(data).opApply(dg); 2260 } 2261 2262 /// ditto 2263 @trusted nothrow @nogc 2264 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2265 @safe nothrow @nogc dg) { return opApply(cast(DG) dg); } 2266 2267 /// ditto 2268 @trusted pure @nogc 2269 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2270 @safe pure @nogc dg) { return opApply(cast(DG) dg); } 2271 2272 /// ditto 2273 @trusted pure nothrow 2274 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2275 @safe pure nothrow dg) { return opApply(cast(DG) dg); } 2276 2277 /// ditto 2278 @trusted @nogc 2279 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2280 @safe @nogc dg) { return opApply(cast(DG) dg); } 2281 2282 /// ditto 2283 @trusted pure 2284 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2285 @safe pure dg) { return opApply(cast(DG) dg); } 2286 2287 /// ditto 2288 @trusted nothrow 2289 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2290 @safe nothrow dg) { return opApply(cast(DG) dg); } 2291 2292 /// ditto 2293 @trusted 2294 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2295 @safe dg) { return opApply(cast(DG) dg); } 2296 2297 /// ditto 2298 @system pure nothrow @nogc 2299 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2300 @system pure nothrow @nogc dg) { return opApply(cast(DG) dg); } 2301 2302 /// ditto 2303 @system nothrow @nogc 2304 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2305 @system nothrow @nogc dg) { return opApply(cast(DG) dg); } 2306 2307 /// ditto 2308 @system pure @nogc 2309 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2310 @system pure @nogc dg) { return opApply(cast(DG) dg); } 2311 2312 /// ditto 2313 @system pure nothrow 2314 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2315 @system pure nothrow dg) { return opApply(cast(DG) dg); } 2316 2317 /// ditto 2318 @system @nogc 2319 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2320 @system @nogc dg) { return opApply(cast(DG) dg); } 2321 2322 /// ditto 2323 @system pure 2324 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2325 @system pure dg) { return opApply(cast(DG) dg); } 2326 2327 /// ditto 2328 @system nothrow 2329 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2330 @system nothrow dg) { return opApply(cast(DG) dg); } 2331 2332 /// ditto 2333 @system 2334 scope int opApply(scope int delegate(IonErrorCode error, scope IonDescribedValue value) 2335 @system dg) { return opApply(cast(DG) dg); } 2336 2337 /++ 2338 For iteration with $(LREF IonDescribedValue) elements. 2339 Throws: `IonException` 2340 +/ 2341 version(GenericOpApply) 2342 scope int opApply(Dg)(scope Dg dg) 2343 if (ParameterTypeTuple!Dg.length == 1) 2344 { 2345 foreach (IonErrorCode error, scope IonDescribedValue value; this) 2346 { 2347 if (_expect(error, false)) 2348 throw error.ionException; 2349 if (auto ret = dg(value)) 2350 return ret; 2351 } 2352 return 0; 2353 } 2354 2355 /++ 2356 For iteration with `IonErrorCode` and $(LREF IonDescribedValue) pairs. 2357 +/ 2358 version(GenericOpApply) 2359 scope int opApply(Dg)(scope Dg dg) 2360 if (ParameterTypeTuple!Dg.length == 2) 2361 { 2362 version(LDC) 2363 pragma(inline, true); 2364 pragma (msg, ParameterTypeTuple!Dg); // foreach with 2 parameters 2365 auto d = data[]; 2366 while (d.length) 2367 { 2368 IonDescribedValue describedValue; 2369 auto error = parseValue(d, describedValue); 2370 if (error == IonErrorCode.nop) 2371 continue; 2372 if (auto ret = dg(error, describedValue)) 2373 return ret; 2374 assert(!error, "User provided delegate MUST break the iteration when error has non-zero value."); 2375 } 2376 return 0; 2377 } 2378 2379 /++ 2380 Params: 2381 serializer = serializer 2382 +/ 2383 void serialize(S)(scope ref S serializer) scope const 2384 { 2385 import mir.ser: beginSexp; 2386 auto state = serializer.beginSexp(this); 2387 foreach (scope IonDescribedValue value; this) 2388 { 2389 serializer.sexpElemBegin; 2390 value.serializeImpl(serializer); 2391 if (false) 2392 value.serializeDummy(serializer); 2393 } 2394 serializer.sexpEnd(state); 2395 } 2396 2397 /// 2398 size_t walkLength() scope const @property @safe pure @nogc 2399 { 2400 size_t length; 2401 IonErrorCode firstError; 2402 foreach (IonErrorCode error, scope IonDescribedValue value; this) 2403 { 2404 length++; 2405 if (error) 2406 { 2407 firstError = error; 2408 break; 2409 } 2410 } 2411 if (firstError) 2412 throw firstError.ionException; 2413 return length; 2414 } 2415 } 2416 2417 /// 2418 version(mir_ion_test) unittest 2419 { 2420 // check parsing with NOP padding: 2421 // (NOP int NOP double NOP) 2422 auto list = IonValue([0xce, 0x91, 0x00, 0x00, 0x21, 0x0c, 0x00, 0x00, 0x48, 0x43, 0x0c, 0x6b, 0xf5, 0x26, 0x34, 0x00, 0x00, 0x00, 0x00]) 2423 .describe.get!IonSexp; 2424 size_t i; 2425 foreach (elem; list) 2426 { 2427 if (i == 0) 2428 assert(elem.get!IonUInt.get!int == 12); 2429 if (i == 1) 2430 assert(elem.get!IonFloat.get!double == 100e13); 2431 i++; 2432 } 2433 assert(i == 2); 2434 } 2435 2436 /++ 2437 $(LERF IonDescribedValue), $(SUBREF exception, IonErrorCode) and symbol id triplet used in the $(LREF IonList) and $(LREF IonSexp). 2438 +/ 2439 struct IonElementWithId 2440 { 2441 /// Ion described value 2442 IonDescribedValue value; 2443 /// Error code 2444 IonErrorCode error; 2445 /// Symbol ID 2446 size_t id; 2447 } 2448 2449 /++ 2450 $(LERF IonDescribedValue) and $(SUBREF exception, IonErrorCode) pair used in the $(LREF IonList) and $(LREF IonSexp)/ 2451 +/ 2452 struct IonElement 2453 { 2454 /// Ion described value 2455 IonDescribedValue value; 2456 /// Error code 2457 IonErrorCode error; 2458 } 2459 2460 /++ 2461 Ion struct (object) 2462 +/ 2463 struct IonStruct 2464 { 2465 /// 2466 IonDescriptor descriptor; 2467 /// 2468 const(ubyte)[] data; 2469 2470 private alias DG = int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) @safe pure nothrow @nogc; 2471 private alias EDG = int delegate(size_t symbolID, scope IonDescribedValue value) @safe pure @nogc; 2472 2473 /// 2474 bool sorted() 2475 @safe pure nothrow @nogc const @property 2476 { 2477 return descriptor.L == 1; 2478 } 2479 2480 /++ 2481 Returns: true if the struct is `null.struct`, `null`, or `()`. 2482 Note: a NOP padding makes in the struct makes it non-empty. 2483 +/ 2484 bool empty() 2485 scope @safe pure nothrow @nogc const @property 2486 { 2487 return data.length == 0; 2488 } 2489 2490 const: 2491 2492 version (D_Exceptions) 2493 { 2494 /++ 2495 +/ 2496 @safe pure @nogc 2497 scope int opApply(scope int delegate(size_t symbolID, scope IonDescribedValue value) @safe pure @nogc dg) 2498 { 2499 return opApply((IonErrorCode error, size_t symbolID, scope IonDescribedValue value) { 2500 if (_expect(error, false)) 2501 throw error.ionException; 2502 return dg(symbolID, value); 2503 }); 2504 } 2505 2506 /// ditto 2507 @trusted @nogc 2508 scope int opApply(scope int delegate(size_t symbolID, scope IonDescribedValue value) 2509 @safe @nogc dg) { return opApply(cast(EDG) dg); } 2510 2511 /// ditto 2512 @trusted pure 2513 scope int opApply(scope int delegate(size_t symbolID, scope IonDescribedValue value) 2514 @safe pure dg) { return opApply(cast(EDG) dg); } 2515 2516 /// ditto 2517 @trusted 2518 scope int opApply(scope int delegate(size_t symbolID, scope IonDescribedValue value) 2519 @safe dg) { return opApply(cast(EDG) dg); } 2520 2521 /// ditto 2522 @system pure @nogc 2523 scope int opApply(scope int delegate(size_t symbolID, scope IonDescribedValue value) 2524 @system pure @nogc dg) { return opApply(cast(EDG) dg); } 2525 2526 /// ditto 2527 @system @nogc 2528 scope int opApply(scope int delegate(size_t symbolID, scope IonDescribedValue value) 2529 @system @nogc dg) { return opApply(cast(EDG) dg); } 2530 2531 /// ditto 2532 @system pure 2533 scope int opApply(scope int delegate(size_t symbolID, scope IonDescribedValue value) 2534 @system pure dg) { return opApply(cast(EDG) dg); } 2535 2536 /// ditto 2537 @system 2538 scope int opApply(scope int delegate(size_t symbolID, scope IonDescribedValue value) 2539 @system dg) { return opApply(cast(EDG) dg); } 2540 } 2541 2542 /++ 2543 +/ 2544 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) @safe pure nothrow @nogc dg) 2545 @safe pure nothrow @nogc 2546 { 2547 auto d = data[]; 2548 while (d.length) 2549 { 2550 size_t symbolID; 2551 IonDescribedValue describedValue; 2552 auto error = parseVarUInt(d, symbolID); 2553 if (!error) 2554 { 2555 describedValue = parseValue(d, error); 2556 if (error == IonErrorCode.nop) 2557 continue; 2558 } 2559 if (auto ret = dg(error, symbolID, describedValue)) 2560 return ret; 2561 assert(!error, "User provided delegate MUST break the iteration when error has non-zero value."); 2562 } 2563 return 0; 2564 } 2565 2566 /// ditto 2567 @trusted nothrow @nogc 2568 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2569 @safe nothrow @nogc dg) { return opApply(cast(DG) dg); } 2570 2571 /// ditto 2572 @trusted pure @nogc 2573 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2574 @safe pure @nogc dg) { return opApply(cast(DG) dg); } 2575 2576 /// ditto 2577 @trusted pure nothrow 2578 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2579 @safe pure nothrow dg) { return opApply(cast(DG) dg); } 2580 2581 /// ditto 2582 @trusted @nogc 2583 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2584 @safe @nogc dg) { return opApply(cast(DG) dg); } 2585 2586 /// ditto 2587 @trusted pure 2588 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2589 @safe pure dg) { return opApply(cast(DG) dg); } 2590 2591 /// ditto 2592 @trusted nothrow 2593 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2594 @safe nothrow dg) { return opApply(cast(DG) dg); } 2595 2596 /// ditto 2597 @trusted 2598 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2599 @safe dg) { return opApply(cast(DG) dg); } 2600 2601 /// ditto 2602 @system pure nothrow @nogc 2603 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2604 @system pure nothrow @nogc dg) { return opApply(cast(DG) dg); } 2605 2606 /// ditto 2607 @system nothrow @nogc 2608 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2609 @system nothrow @nogc dg) { return opApply(cast(DG) dg); } 2610 2611 /// ditto 2612 @system pure @nogc 2613 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2614 @system pure @nogc dg) { return opApply(cast(DG) dg); } 2615 2616 /// ditto 2617 @system pure nothrow 2618 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2619 @system pure nothrow dg) { return opApply(cast(DG) dg); } 2620 2621 /// ditto 2622 @system @nogc 2623 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2624 @system @nogc dg) { return opApply(cast(DG) dg); } 2625 2626 /// ditto 2627 @system pure 2628 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2629 @system pure dg) { return opApply(cast(DG) dg); } 2630 2631 /// ditto 2632 @system nothrow 2633 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2634 @system nothrow dg) { return opApply(cast(DG) dg); } 2635 2636 /// ditto 2637 @system 2638 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID, scope IonDescribedValue value) 2639 @system dg) { return opApply(cast(DG) dg); } 2640 2641 /++ 2642 For iteration with $(LREF IonDescribedValue) pairs. 2643 Throws: `IonException` 2644 +/ 2645 version(GenericOpApply) 2646 scope int opApply(Dg)(scope Dg dg) 2647 if (ParameterTypeTuple!Dg.length == 2) 2648 { 2649 foreach (IonErrorCode error, size_t symbolID, scope IonDescribedValue value; this) 2650 { 2651 if (_expect(error, false)) 2652 throw error.ionException; 2653 if (auto ret = dg(symbolID, value)) 2654 return ret; 2655 } 2656 return 0; 2657 } 2658 2659 /++ 2660 For iteration with `size_t` (symbol ID), `IonErrorCode`, and $(LREF IonDescribedValue) triplets. 2661 +/ 2662 version(GenericOpApply) 2663 scope int opApply(Dg)(scope Dg dg) 2664 if (ParameterTypeTuple!Dg.length == 3) 2665 { 2666 version(LDC) 2667 pragma(inline, true); 2668 pragma (msg, ParameterTypeTuple!Dg); // foreach with 2 parameters 2669 auto d = data[]; 2670 while (d.length) 2671 { 2672 size_t symbolID; 2673 IonDescribedValue describedValue; 2674 auto error = parseVarUInt(d, symbolID); 2675 if (!error) 2676 { 2677 error = parseValue(d, describedValue); 2678 if (error == IonErrorCode.nop) 2679 continue; 2680 } 2681 import core.lifetime: move; 2682 if (auto ret = dg(move(error), move(symbolID), move(describedValue))) 2683 return ret; 2684 assert(!error, "User provided delegate MUST break the iteration when error has non-zero value."); 2685 } 2686 return 0; 2687 } 2688 2689 /++ 2690 Params: 2691 serializer = serializer 2692 +/ 2693 void serialize(S)(scope ref S serializer) scope const 2694 { 2695 import mir.ser: beginStruct; 2696 auto state = serializer.beginStruct(this); 2697 foreach (size_t symbolID, scope IonDescribedValue value; this) 2698 { 2699 serializer.putKeyId(symbolID); 2700 value.serializeImpl(serializer); 2701 if (false) 2702 value.serializeDummy(serializer); 2703 } 2704 serializer.structEnd(state); 2705 } 2706 2707 /// 2708 @safe pure nothrow @nogc 2709 IonStructWithSymbols withSymbols(return scope const(char[])[] symbolTable) return scope 2710 { 2711 return IonStructWithSymbols(this, symbolTable); 2712 } 2713 2714 /// 2715 size_t walkLength(out IonErrorCode firstError) scope const @property @safe pure @nogc 2716 { 2717 size_t length; 2718 foreach (IonErrorCode error, size_t symbolID, scope IonDescribedValue value; this) 2719 { 2720 length++; 2721 if (error) 2722 { 2723 firstError = error; 2724 break; 2725 } 2726 } 2727 return length; 2728 } 2729 2730 /// 2731 size_t walkLength() scope const @property @safe pure @nogc 2732 { 2733 IonErrorCode firstError; 2734 auto length = this.walkLength(firstError); 2735 if (firstError) 2736 throw firstError.ionException; 2737 return length; 2738 } 2739 } 2740 2741 /// 2742 @safe pure 2743 version(mir_ion_test) unittest 2744 { 2745 // null.struct 2746 assert(IonValue([0xDF]).describe.get!IonNull == IonNull(IonTypeCode.struct_)); 2747 2748 // empty struct 2749 auto ionStruct = IonValue([0xD0]).describe.get!IonStruct; 2750 size_t i; 2751 foreach (symbolID, elem; ionStruct) 2752 i++; 2753 assert(i == 0); 2754 2755 // added two 2-bytes NOP padings 0x8F 0x00 2756 ionStruct = IonValue([0xDE, 0x91, 0x8F, 0x00, 0x8A, 0x21, 0x0C, 0x8B, 0x48, 0x43, 0x0C, 0x6B, 0xF5, 0x26, 0x34, 0x00, 0x00, 0x8F, 0x00]) 2757 .describe 2758 .get!IonStruct; 2759 2760 foreach (symbolID, elem; ionStruct) 2761 { 2762 if (i == 0) 2763 { 2764 assert(symbolID == 10); 2765 assert(elem.get!IonUInt.get!int == 12); 2766 } 2767 if (i == 1) 2768 { 2769 assert(symbolID == 11); 2770 assert(elem.get!IonFloat.get!double == 100e13); 2771 } 2772 i++; 2773 } 2774 assert(i == 2); 2775 } 2776 2777 2778 /++ 2779 Ion struct (object) with a symbol table 2780 +/ 2781 struct IonStructWithSymbols 2782 { 2783 /// 2784 IonStruct ionStruct; 2785 /// 2786 const(char[])[] symbolTable; 2787 2788 private alias DG = int delegate(IonErrorCode error, scope const(char)[], scope IonDescribedValue value) @safe pure nothrow @nogc; 2789 private alias EDG = int delegate(scope const(char)[], scope IonDescribedValue value) @safe pure @nogc; 2790 2791 /// 2792 bool sorted() 2793 @safe pure nothrow @nogc const @property 2794 { 2795 return ionStruct.sorted; 2796 } 2797 2798 /++ 2799 Returns: true if the struct is `null.struct`, `null`, or `()`. 2800 Note: a NOP padding makes in the struct makes it non-empty. 2801 +/ 2802 bool empty() 2803 scope @safe pure nothrow @nogc const @property 2804 { 2805 return ionStruct.empty; 2806 } 2807 2808 const: 2809 2810 version (D_Exceptions) 2811 { 2812 /++ 2813 +/ 2814 @safe pure @nogc 2815 scope int opApply(scope int delegate(scope const(char)[] symbol, scope IonDescribedValue value) @safe pure @nogc dg) 2816 { 2817 return opApply((IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) { 2818 if (_expect(error, false)) 2819 throw error.ionException; 2820 return dg(symbol, value); 2821 }); 2822 } 2823 2824 /// ditto 2825 @trusted @nogc 2826 scope int opApply(scope int delegate(scope const(char)[] symbol, scope IonDescribedValue value) 2827 @safe @nogc dg) { return opApply(cast(EDG) dg); } 2828 2829 /// ditto 2830 @trusted pure 2831 scope int opApply(scope int delegate(scope const(char)[] symbol, scope IonDescribedValue value) 2832 @safe pure dg) { return opApply(cast(EDG) dg); } 2833 2834 /// ditto 2835 @trusted 2836 scope int opApply(scope int delegate(scope const(char)[] symbol, scope IonDescribedValue value) 2837 @safe dg) { return opApply(cast(EDG) dg); } 2838 2839 /// ditto 2840 @system pure @nogc 2841 scope int opApply(scope int delegate(scope const(char)[] symbol, scope IonDescribedValue value) 2842 @system pure @nogc dg) { return opApply(cast(EDG) dg); } 2843 2844 /// ditto 2845 @system @nogc 2846 scope int opApply(scope int delegate(scope const(char)[] symbol, scope IonDescribedValue value) 2847 @system @nogc dg) { return opApply(cast(EDG) dg); } 2848 2849 /// ditto 2850 @system pure 2851 scope int opApply(scope int delegate(scope const(char)[] symbol, scope IonDescribedValue value) 2852 @system pure dg) { return opApply(cast(EDG) dg); } 2853 2854 /// ditto 2855 @system 2856 scope int opApply(scope int delegate(scope const(char)[] symbol, scope IonDescribedValue value) 2857 @system dg) { return opApply(cast(EDG) dg); } 2858 } 2859 2860 /++ 2861 +/ 2862 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) @safe pure nothrow @nogc dg) 2863 @safe pure nothrow @nogc 2864 { 2865 return ionStruct.opApply((IonErrorCode error, size_t symbolId, scope IonDescribedValue value) { 2866 scope const(char)[] symbol; 2867 if (!error) 2868 { 2869 if (symbolId < symbolTable.length) 2870 { 2871 symbol = symbolTable[symbolId]; 2872 } 2873 else 2874 { 2875 error = IonErrorCode.symbolIdIsTooLargeForTheCurrentSymbolTable; 2876 } 2877 } 2878 return dg(error, symbol, value); 2879 }); 2880 } 2881 2882 /// ditto 2883 @trusted nothrow @nogc 2884 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2885 @safe nothrow @nogc dg) { return opApply(cast(DG) dg); } 2886 2887 /// ditto 2888 @trusted pure @nogc 2889 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2890 @safe pure @nogc dg) { return opApply(cast(DG) dg); } 2891 2892 /// ditto 2893 @trusted pure nothrow 2894 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2895 @safe pure nothrow dg) { return opApply(cast(DG) dg); } 2896 2897 /// ditto 2898 @trusted @nogc 2899 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2900 @safe @nogc dg) { return opApply(cast(DG) dg); } 2901 2902 /// ditto 2903 @trusted pure 2904 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2905 @safe pure dg) { return opApply(cast(DG) dg); } 2906 2907 /// ditto 2908 @trusted nothrow 2909 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2910 @safe nothrow dg) { return opApply(cast(DG) dg); } 2911 2912 /// ditto 2913 @trusted 2914 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2915 @safe dg) { return opApply(cast(DG) dg); } 2916 2917 /// ditto 2918 @system pure nothrow @nogc 2919 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2920 @system pure nothrow @nogc dg) { return opApply(cast(DG) dg); } 2921 2922 /// ditto 2923 @system nothrow @nogc 2924 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2925 @system nothrow @nogc dg) { return opApply(cast(DG) dg); } 2926 2927 /// ditto 2928 @system pure @nogc 2929 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2930 @system pure @nogc dg) { return opApply(cast(DG) dg); } 2931 2932 /// ditto 2933 @system pure nothrow 2934 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2935 @system pure nothrow dg) { return opApply(cast(DG) dg); } 2936 2937 /// ditto 2938 @system @nogc 2939 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2940 @system @nogc dg) { return opApply(cast(DG) dg); } 2941 2942 /// ditto 2943 @system pure 2944 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2945 @system pure dg) { return opApply(cast(DG) dg); } 2946 2947 /// ditto 2948 @system nothrow 2949 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2950 @system nothrow dg) { return opApply(cast(DG) dg); } 2951 2952 /// ditto 2953 @system 2954 scope int opApply(scope int delegate(IonErrorCode error, scope const(char)[] symbol, scope IonDescribedValue value) 2955 @system dg) { return opApply(cast(DG) dg); } 2956 2957 /++ 2958 Returns: $(LREF IonDescribedValue) 2959 +/ 2960 auto opIndex(scope const(char)[] symbol) const @safe pure // @nogc DIP1008 2961 { 2962 foreach (key, scope IonDescribedValue value; this) 2963 { 2964 if (key == symbol) 2965 { 2966 return value; 2967 } 2968 } 2969 import mir.serde: SerdeMirException; 2970 throw new SerdeMirException("Ion struct doesn't contain member ", symbol); 2971 } 2972 2973 import mir.algebraic: Nullable; 2974 2975 /++ 2976 +/ 2977 Nullable!IonDescribedValue opBinaryRight(string op : "in")(scope const(char)[] symbol) const @safe pure @nogc 2978 { 2979 foreach (key, value; this) 2980 { 2981 if (key == symbol) 2982 { 2983 return typeof(return)(value); 2984 } 2985 } 2986 return typeof(return).init; 2987 } 2988 2989 /++ 2990 Params: 2991 serializer = serializer 2992 +/ 2993 void serialize(S)(scope ref S serializer) scope const 2994 { 2995 ionStruct.serialize(serializer); 2996 } 2997 } 2998 2999 /++ 3000 Ion Annotation Wrapper 3001 +/ 3002 struct IonAnnotationWrapper 3003 { 3004 /// 3005 IonAnnotations annotations; 3006 /// 3007 IonDescribedValue value; 3008 3009 /++ 3010 Params: 3011 serializer = serializer 3012 +/ 3013 void serialize(S)(scope ref S serializer) scope const 3014 { 3015 auto state = serializer.annotationWrapperBegin; 3016 foreach(symbolID; annotations) 3017 { 3018 serializer.putAnnotationId(symbolID); 3019 } 3020 auto annotationsState = serializer.annotationsEnd(state); 3021 3022 value.serializeImpl(serializer); 3023 if (false) 3024 value.serializeDummy(serializer); 3025 3026 serializer.annotationWrapperEnd(annotationsState, state); 3027 } 3028 } 3029 3030 /// 3031 @safe pure 3032 version(mir_ion_test) unittest 3033 { 3034 // null.struct 3035 3036 auto uw = IonValue([0xE7, 0x82, 0x8A, 0x8B, 0x53, 0xC3, 0x04, 0x65]) 3037 .describe 3038 .get!IonAnnotationWrapper; 3039 assert(uw.value.get!IonDecimal.get!double == 1.125); 3040 3041 size_t i; 3042 foreach (symbolID; uw.annotations) 3043 { 3044 if (i == 0) 3045 { 3046 assert(symbolID == 10); 3047 } 3048 if (i == 1) 3049 { 3050 assert(symbolID == 11); 3051 } 3052 i++; 3053 } 3054 assert(i == 2); 3055 } 3056 3057 /++ 3058 List of annotations represented as symbol IDs. 3059 +/ 3060 struct IonAnnotations 3061 { 3062 /// 3063 const(ubyte)[] data; 3064 private alias DG = int delegate(IonErrorCode error, size_t symbolID) @safe pure nothrow @nogc; 3065 private alias EDG = int delegate(size_t symbolID) @safe pure @nogc; 3066 3067 /++ 3068 Returns: true if no annotations provided. 3069 +/ 3070 bool empty() 3071 scope @safe pure nothrow @nogc const @property 3072 { 3073 return data.length == 0; 3074 } 3075 3076 /// 3077 IonErrorCode pick(scope ref size_t symbolID) 3078 @safe pure nothrow @nogc scope 3079 { 3080 assert(!empty); 3081 return parseVarUInt(data, symbolID); 3082 } 3083 3084 const: 3085 3086 version (D_Exceptions) 3087 { 3088 /++ 3089 +/ 3090 @safe pure @nogc 3091 scope int opApply(scope int delegate(size_t symbolID) @safe pure @nogc dg) 3092 { 3093 return opApply((IonErrorCode error, size_t symbolID) { 3094 if (_expect(error, false)) 3095 throw error.ionException; 3096 return dg(symbolID); 3097 }); 3098 } 3099 3100 /// ditto 3101 @trusted @nogc 3102 scope int opApply(scope int delegate(size_t symbolID) 3103 @safe @nogc dg) { return opApply(cast(EDG) dg); } 3104 3105 /// ditto 3106 @trusted pure 3107 scope int opApply(scope int delegate(size_t symbolID) 3108 @safe pure dg) { return opApply(cast(EDG) dg); } 3109 3110 /// ditto 3111 @trusted 3112 scope int opApply(scope int delegate(size_t symbolID) 3113 @safe dg) { return opApply(cast(EDG) dg); } 3114 3115 /// ditto 3116 @system pure @nogc 3117 scope int opApply(scope int delegate(size_t symbolID) 3118 @system pure @nogc dg) { return opApply(cast(EDG) dg); } 3119 3120 /// ditto 3121 @system @nogc 3122 scope int opApply(scope int delegate(size_t symbolID) 3123 @system @nogc dg) { return opApply(cast(EDG) dg); } 3124 3125 /// ditto 3126 @system pure 3127 scope int opApply(scope int delegate(size_t symbolID) 3128 @system pure dg) { return opApply(cast(EDG) dg); } 3129 3130 /// ditto 3131 @system 3132 scope int opApply(scope int delegate(size_t symbolID) 3133 @system dg) { return opApply(cast(EDG) dg); } 3134 } 3135 3136 /++ 3137 +/ 3138 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) @safe pure nothrow @nogc dg) 3139 @safe pure nothrow @nogc 3140 { 3141 auto d = data[]; 3142 while (d.length) 3143 { 3144 size_t symbolID; 3145 auto error = parseVarUInt(d, symbolID); 3146 if (auto ret = dg(error, symbolID)) 3147 return ret; 3148 assert(!error, "User provided delegate MUST break the iteration when error has non-zero value."); 3149 } 3150 return 0; 3151 } 3152 3153 /// ditto 3154 @trusted nothrow @nogc 3155 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3156 @safe nothrow @nogc dg) { return opApply(cast(DG) dg); } 3157 3158 /// ditto 3159 @trusted pure @nogc 3160 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3161 @safe pure @nogc dg) { return opApply(cast(DG) dg); } 3162 3163 /// ditto 3164 @trusted pure nothrow 3165 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3166 @safe pure nothrow dg) { return opApply(cast(DG) dg); } 3167 3168 /// ditto 3169 @trusted @nogc 3170 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3171 @safe @nogc dg) { return opApply(cast(DG) dg); } 3172 3173 /// ditto 3174 @trusted pure 3175 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3176 @safe pure dg) { return opApply(cast(DG) dg); } 3177 3178 /// ditto 3179 @trusted nothrow 3180 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3181 @safe nothrow dg) { return opApply(cast(DG) dg); } 3182 3183 /// ditto 3184 @trusted 3185 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3186 @safe dg) { return opApply(cast(DG) dg); } 3187 3188 /// ditto 3189 @system pure nothrow @nogc 3190 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3191 @system pure nothrow @nogc dg) { return opApply(cast(DG) dg); } 3192 3193 /// ditto 3194 @system nothrow @nogc 3195 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3196 @system nothrow @nogc dg) { return opApply(cast(DG) dg); } 3197 3198 /// ditto 3199 @system pure @nogc 3200 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3201 @system pure @nogc dg) { return opApply(cast(DG) dg); } 3202 3203 /// ditto 3204 @system pure nothrow 3205 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3206 @system pure nothrow dg) { return opApply(cast(DG) dg); } 3207 3208 /// ditto 3209 @system @nogc 3210 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3211 @system @nogc dg) { return opApply(cast(DG) dg); } 3212 3213 /// ditto 3214 @system pure 3215 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3216 @system pure dg) { return opApply(cast(DG) dg); } 3217 3218 /// ditto 3219 @system nothrow 3220 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3221 @system nothrow dg) { return opApply(cast(DG) dg); } 3222 3223 /// ditto 3224 @system 3225 scope int opApply(scope int delegate(IonErrorCode error, size_t symbolID) 3226 @system dg) { return opApply(cast(DG) dg); } 3227 } 3228 3229 package IonErrorCode parseVarUInt(bool checkInput = true, U)(scope ref const(ubyte)[] data, scope out U result) 3230 @safe pure nothrow @nogc 3231 if (is(U == ubyte) || is(U == ushort) || is(U == uint) || is(U == ulong)) 3232 { 3233 version (LDC) pragma(inline, true); 3234 enum mLength = U(1) << (U.sizeof * 8 / 7 * 7); 3235 for(;;) 3236 { 3237 static if (checkInput) 3238 { 3239 if (_expect(data.length == 0, false)) 3240 return IonErrorCode.unexpectedEndOfData; 3241 } 3242 else 3243 { 3244 assert(data.length); 3245 } 3246 ubyte b = data[0]; 3247 data = data[1 .. $]; 3248 result <<= 7; 3249 result |= b & 0x7F; 3250 if (cast(byte)b < 0) 3251 return IonErrorCode.none; 3252 static if (checkInput) 3253 { 3254 if (_expect(result >= mLength, false)) 3255 return IonErrorCode.overflowInParseVarUInt; 3256 } 3257 else 3258 { 3259 assert(result < mLength); 3260 } 3261 } 3262 } 3263 3264 private IonErrorCode parseVarInt(S)(scope ref const(ubyte)[] data, scope out S result) 3265 @safe pure nothrow @nogc 3266 if (is(S == byte) || is(S == short) || is(S == int) || is(S == long)) 3267 { 3268 bool neg; 3269 Unsigned!S unsigned; 3270 if (auto error = parseVarInt(data, unsigned, neg)) 3271 return error; 3272 result = neg ? cast(S)(0-cast(S)unsigned) : unsigned; 3273 return IonErrorCode.none; 3274 } 3275 3276 private IonErrorCode parseVarInt(U)(scope ref const(ubyte)[] data, scope out U result, scope out bool neg) 3277 @safe pure nothrow @nogc 3278 if (is(U == ubyte) || is(U == ushort) || is(U == uint) || is(U == ulong)) 3279 { 3280 version (LDC) pragma(inline, true); 3281 enum mLength = U(1) << (U.sizeof * 8 / 7 * 7 - 1); 3282 U length; 3283 if (_expect(data.length == 0, false)) 3284 return IonErrorCode.unexpectedEndOfData; 3285 ubyte b = data[0]; 3286 data = data[1 .. $]; 3287 if (b & 0x40) 3288 { 3289 neg = true; 3290 b ^= 0x40; 3291 } 3292 length = b & 0x7F; 3293 goto L; 3294 for(;;) 3295 { 3296 if (_expect(data.length == 0, false)) 3297 return IonErrorCode.unexpectedEndOfData; 3298 b = data[0]; 3299 data = data[1 .. $]; 3300 length <<= 7; 3301 length |= b & 0x7F; 3302 L: 3303 if (cast(byte)b < 0) 3304 { 3305 result = length; 3306 return IonErrorCode.none; 3307 } 3308 if (_expect(length >= mLength, false)) 3309 return IonErrorCode.overflowInParseVarInt; 3310 } 3311 } 3312 3313 package IonDescribedValue parseValue()(ref return scope const(ubyte)[] data, out IonErrorCode error) 3314 @safe pure nothrow @nogc 3315 { 3316 version (LDC) pragma(inline, true); 3317 3318 if (_expect(data.length == 0, false)) 3319 { 3320 error = IonErrorCode.unexpectedEndOfData; 3321 return IonDescribedValue.init; 3322 } 3323 auto descriptorPtr = &data[0]; 3324 data = data[1 .. $]; 3325 ubyte descriptorData = *descriptorPtr; 3326 3327 if (_expect(descriptorData > 0xEE, false)) 3328 { 3329 error = IonErrorCode.illegalTypeDescriptor; 3330 return IonDescribedValue.init; 3331 } 3332 3333 auto describedValue = IonDescribedValue(IonDescriptor(descriptorPtr)); 3334 3335 const L = describedValue.descriptor.L; 3336 const type = describedValue.descriptor.type; 3337 // if null 3338 if (L == 0xF) 3339 return describedValue; 3340 // if bool 3341 if (type == IonTypeCode.bool_) 3342 { 3343 if (_expect(L > 1, false)) 3344 error = IonErrorCode.illegalTypeDescriptor; 3345 return describedValue; 3346 } 3347 size_t length = L; 3348 // if large 3349 if (length == 0xE) 3350 { 3351 error = parseVarUInt(data, length); 3352 if (error) 3353 return IonDescribedValue.init; 3354 } 3355 else 3356 if (descriptorData == 0xD1) 3357 { 3358 error = parseVarUInt(data, length); 3359 if (error) 3360 return IonDescribedValue.init; 3361 if (length == 0) 3362 { 3363 error = IonErrorCode.emptyOrderedStruct; 3364 return IonDescribedValue.init; 3365 } 3366 } 3367 if (_expect(length > data.length, false)) 3368 { 3369 error = IonErrorCode.unexpectedEndOfData; 3370 return IonDescribedValue.init; 3371 } 3372 3373 if (_expect(type == IonTypeCode.nInt, false)) 3374 { 3375 if (length) do 3376 { 3377 if (data[0]) 3378 goto R; 3379 data = data[1 .. $]; 3380 } 3381 while(--length); 3382 error = IonErrorCode.negativeIntegerZero; 3383 return IonDescribedValue.init; 3384 } 3385 R: 3386 describedValue.data = data[0 .. length]; 3387 data = data[length .. $]; 3388 // NOP Padding 3389 error = type == IonTypeCode.null_ ? IonErrorCode.nop : IonErrorCode.none; 3390 return describedValue; 3391 } 3392 3393 private F parseFloating(F)(scope const(ubyte)[] data) 3394 @trusted pure nothrow @nogc 3395 if (isFloatingPoint!F) 3396 { 3397 version (LDC) pragma(inline, true); 3398 3399 enum n = F.sizeof; 3400 static if (n == 4) 3401 alias U = uint; 3402 else 3403 static if (n == 8) 3404 alias U = ulong; 3405 else 3406 static if (n == 16) 3407 alias U = ucent; 3408 else static assert(0); 3409 3410 assert(data.length == n); 3411 3412 U num; 3413 if (__ctfe) 3414 { 3415 static foreach_reverse (i; 0 .. n) 3416 { 3417 num <<= 8; 3418 num |= data.ptr[i]; 3419 } 3420 } 3421 else 3422 { 3423 num = (cast(U[1])cast(ubyte[n])data.ptr[0 .. n])[0]; 3424 } 3425 version (LittleEndian) 3426 { 3427 import core.bitop : bswap; 3428 num = bswap(num); 3429 } 3430 return num.unsignedDataToFloating; 3431 } 3432 3433 private auto unsignedDataToFloating(T)(const T data) 3434 @trusted pure nothrow @nogc 3435 if (__traits(isUnsigned, T) && T.sizeof >= 4) 3436 { 3437 static if (T.sizeof == 4) 3438 alias F = float; 3439 else 3440 static if (T.sizeof == 8) 3441 alias F = double; 3442 else 3443 alias F = quadruple; 3444 3445 version(all) 3446 { 3447 return *cast(F*)&data; 3448 } 3449 else 3450 { 3451 T num = data; 3452 bool sign = cast(bool)(num >> (T.sizeof * 8 - 1)); 3453 num &= num.max >> 1; 3454 if (num == 0) 3455 return F(sign ? -0.0f : 0.0f); 3456 int exp = cast(int) (num >> (F.mant_dig - 1)); 3457 num &= (T(1) << (F.mant_dig - 1)) - 1; 3458 if (exp) 3459 { 3460 if (exp == (T(1) << (T.sizeof * 8 - F.mant_dig)) - 1) 3461 { 3462 F ret = num == 0 ? F.infinity : F.nan; 3463 if (sign) 3464 ret = -ret; 3465 return ret; 3466 } 3467 exp -= 1; 3468 num |= T(1) << (F.mant_dig - 1); 3469 } 3470 3471 exp -= F.mant_dig - F.min_exp; 3472 F ret = num; 3473 import mir.math.ieee: ldexp; 3474 // ret = ldexp(ret, exp); 3475 ret *= 2.0 ^^ exp; 3476 if (sign) 3477 ret = -ret; 3478 assert(data == cast(ulong)*cast(T*) &ret); 3479 return ret; 3480 } 3481 } 3482 3483 @safe pure nothrow @nogc 3484 unittest 3485 { 3486 assert(unsignedDataToFloating(1UL) == double.min_normal * double.epsilon); 3487 assert(unsignedDataToFloating(1U) == float.min_normal * float.epsilon); 3488 3489 assert(unsignedDataToFloating(0xFFF0000000000000U) == -double.infinity); 3490 assert(unsignedDataToFloating(0x4008000000000000U) == 3.0); 3491 assert(unsignedDataToFloating(0x4028000000000000U) == 12.0); 3492 assert(unsignedDataToFloating(0x430c6bf526340000U) == 1e15); 3493 assert(unsignedDataToFloating(1UL) == double.min_normal * double.epsilon); 3494 assert(unsignedDataToFloating(1U) == float.min_normal * float.epsilon); 3495 3496 static assert(unsignedDataToFloating(0xFFF0000000000000U) == -double.infinity); 3497 static assert(unsignedDataToFloating(0x4008000000000000U) == 3.0, unsignedDataToFloating(0x4008000000000000U)); 3498 static assert(unsignedDataToFloating(0x4028000000000000U) == 12.0, unsignedDataToFloating(0x4028000000000000U)); 3499 static assert(unsignedDataToFloating(0x430c6bf526340000U) == 1e15, unsignedDataToFloating(0x430c6bf526340000U)); 3500 static assert(unsignedDataToFloating(1UL) == double.min_normal * double.epsilon); 3501 static assert(unsignedDataToFloating(1U) == float.min_normal * float.epsilon); 3502 }