1 /// \file HiBON.d 2 3 /** 4 * @brief Implements HiBON 5 * Hash-invariant Binary Object Notation 6 * Is inspired by BSON but us not compatible 7 * 8 * @see 9 * <a href="http://bsonspec.org/">BSON - Binary JSON</a> 10 */ 11 module tagion.betterC.hibon.HiBON; 12 13 @nogc: 14 //import std.container : RedBlackTree; 15 //import std.format; 16 import std.meta : staticIndexOf; 17 18 //import std.algorithm.iteration : map, fold, each; 19 import std.traits : EnumMembers, ForeachType, Unqual, isMutable, isBasicType, PointerTarget, 20 isAssociativeArray; 21 import std.meta : AliasSeq; 22 import std.range : enumerate, isInputRange; 23 24 //import std.conv : to; 25 //import std.typecons : TypedefType; 26 27 import tagion.betterC.hibon.BigNumber; 28 import tagion.betterC.hibon.Document; 29 import tagion.betterC.hibon.HiBONBase; 30 import tagion.betterC.utils.Bailout; 31 import tagion.betterC.utils.Basic; 32 import tagion.betterC.utils.BinBuffer; 33 import tagion.betterC.utils.Memory; 34 import tagion.betterC.utils.RBTree; 35 import tagion.betterC.utils.Text; 36 import LEB128 = tagion.betterC.utils.LEB128; 37 38 import tagion.betterC.utils.platform; 39 40 //import core.stdc.stdio; 41 42 import std.stdio; 43 44 HiBONT HiBON() { 45 HiBONT result = HiBONT(RBTree!(HiBONT.Member*)(), true, false); 46 return result; 47 } 48 49 /** 50 * HiBON is a generate obje52ct of the HiBON format 51 */ 52 struct HiBONT { 53 @nogc: 54 /** 55 * Gets the internal buffer 56 * @return the buffer of the HiBON document 57 */ 58 alias Members = RBTreeT!(Member*); 59 60 // RedBlackTree!(Member, (a, b) => (less_than(a.key, b.key))); 61 private { 62 Members _members; 63 bool _owns; /// show is it owning 64 bool _readonly; /// true if read only 65 bool _self_destruct; /// true if self-destruced 66 BinBuffer _buffer; 67 } 68 69 uint error; 70 71 alias Value = ValueT!(true, HiBONT*, Document); 72 73 /** 74 * Destructor 75 */ 76 ~this() { 77 dispose; 78 } 79 80 void dispose() { 81 if (_owns) { 82 _members.dispose; 83 } 84 else { 85 _members.surrender; 86 } 87 _buffer.dispose; 88 if (_self_destruct) { 89 HiBONT* self = &this; 90 91 92 93 .dispose!false(self); 94 } 95 } 96 97 invariant { 98 assert(_owns || (!_owns && _readonly)); 99 } 100 101 /** 102 * Calculate the size in bytes of HiBON payload 103 * @return the size in bytes 104 */ 105 size_t size() const { 106 size_t result; 107 foreach (n; _members[]) { 108 result += n.size; 109 } 110 if (result > 0) { 111 return result; //+calc_size(result); 112 } 113 else { 114 return ubyte.sizeof; 115 } 116 } 117 118 /** 119 * Calculated the size in bytes of serialized HiBON 120 * @return the size in bytes 121 */ 122 size_t serialize_size() const { 123 auto _size = size; 124 if (_size !is ubyte.sizeof) { 125 _size += LEB128.calc_size(_size); 126 } 127 return _size; 128 } 129 130 /** 131 * Expropriate the members to the return 132 * @return The new owner of the members 133 */ 134 HiBONT* expropriate() { 135 auto result = create!(HiBONT); 136 // Surrender the RBTree to the result; 137 result._members = _members.expropriate; 138 result._owns = true; 139 result._self_destruct = true; 140 _readonly = true; 141 _owns = false; 142 143 // expropriate; 144 return result; 145 } 146 147 @property bool readonly() const pure { 148 return _readonly; 149 } 150 151 @property bool owns() const pure { 152 return _owns; 153 } 154 155 /** 156 * Generated the serialized HiBON 157 * @return the byte stream 158 */ 159 immutable(ubyte[]) serialize() { 160 _buffer.recreate(serialize_size); 161 append(_buffer); 162 return _buffer.serialize; 163 } 164 165 // /** 166 // Helper function to append 167 // */ 168 private void append(ref BinBuffer buffer) const { 169 if (_members.empty) { 170 buffer.write(ubyte(0)); 171 } 172 else { 173 uint size; 174 foreach (m; _members[]) { 175 size += m.size; 176 } 177 LEB128.encode(buffer, size); 178 foreach (n; _members[]) { 179 n.append(buffer); 180 } 181 } 182 } 183 184 /** 185 ** Internal Member in the HiBON class 186 */ 187 struct Member { 188 @nogc: 189 private { 190 char[] _key; 191 Type _type; 192 Value _value; 193 } 194 195 int opCmp(ref const(Member*) b) const pure { 196 return opCmp(b._key); 197 } 198 199 int opCmp(const(char[]) key) const pure { 200 int res = 1; 201 if (this._key.length == key.length) { 202 res = 0; 203 foreach (i, elem; key) { 204 if (this._key[i] != elem) { 205 res = 1; 206 } 207 } 208 } 209 else if (this._key < key) { 210 res = -1; 211 } 212 return res; 213 } 214 215 bool opEquals(T)(T b) const pure { 216 return opCmp(b) == 0; 217 } 218 219 alias CastTypes = AliasSeq!(uint, int, ulong, long, string); 220 /** 221 * Construct a Member 222 * @param x = the parameter value 223 * @param key = the name of the member 224 */ 225 this(T)(T x, in const(char[]) key) { 226 227 228 229 .create(this._key, key); 230 void _init(S)(S x) { 231 enum E = Value.asType!S; 232 this._type = E; 233 static if (.isArray(E)) { 234 alias U = Unqual!(ForeachType!S); 235 U[] temp_x; 236 temp_x.create(x); 237 this._value = cast(S) temp_x; 238 } 239 else static if (E is Type.BIGINT) { 240 this._value = x; 241 } 242 else { 243 this._value = cast(UnqualT) x; 244 } 245 246 } 247 248 alias UnqualT = Unqual!T; 249 enum E = Value.asType!UnqualT; 250 static if (E is Type.NONE) { 251 alias CastT = CastTo!(UnqualT, CastTypes); 252 static assert(!is(CastT == void), "Type " ~ T.stringof ~ " is not valid"); 253 _init(x); 254 } 255 else { 256 _init(x); 257 } 258 259 } 260 261 private this(in const(char[]) key) { 262 _key = Text(key).expropriate; 263 } 264 265 private this(in size_t index) { 266 _key = Text(index).expropriate; 267 } 268 269 static Member* create(T)(T x, in const(char[]) key) { 270 // auto new_member=Member(x, key); 271 // scope(exit) { 272 // new_member._key=null; 273 // } 274 auto result = .create!Member(x, key); 275 // result._key=new_nember._key; 276 // result._type=new_member._type; 277 // result._value=new_member._value; 278 return result; 279 } 280 281 @property const pure { 282 Type type() { 283 return _type; 284 } 285 286 string key() { 287 return cast(immutable) _key; 288 } 289 290 Value value() { 291 return _value; 292 } 293 294 size_t key_size() { 295 uint index; 296 if (is_index(_key, index)) { 297 return ubyte.sizeof + LEB128.calc_size(index); 298 } 299 return LEB128.calc_size(_key.length) + _key.length; 300 } 301 } 302 303 ~this() { 304 dispose; 305 } 306 307 void dispose() { 308 with (Type) { 309 TypeCase: 310 final switch (type) { 311 static foreach (E; EnumMembers!Type) { 312 case E: 313 static if (.isArray(E)) { 314 alias U = Unqual!(ForeachType!(Value.TypeT!E)); 315 auto remove_this = cast(U[]) value.by!E; 316 317 318 319 .dispose(remove_this); 320 } 321 else static if (E is Type.DOCUMENT) { 322 alias T = Unqual!(PointerTarget!(Value.TypeT!E)); 323 auto sub = value.by!(E); 324 auto remove_this = cast(T*)(value.by!(E)); 325 remove_this.dispose; 326 } 327 break TypeCase; 328 } 329 } 330 } 331 _key.dispose; 332 } 333 334 /** 335 * If the value of the Member contains a Document it returns it or else an error is asserted 336 * @return the value as a Document 337 */ 338 const(HiBONT*) document() const pure 339 in { 340 assert(type is Type.DOCUMENT); 341 } 342 do { 343 return value.document; 344 } 345 346 /** 347 * @return the value as type T 348 * @throw if the member does not match the type T and HiBONException is thrown 349 */ 350 const(T) get(T)() const { 351 enum E = Value.asType!T; 352 353 354 355 .check(E is type, message("Expected HiBON type %s but apply type %s (%s)", type, E, T 356 .stringof)); 357 return value.by!E; 358 } 359 360 /** 361 * @return the value as HiBON Type E 362 * @throw if the member does not match the type T and HiBONException is thrown 363 */ 364 auto by(Type type)() inout { 365 return value.by!type; 366 } 367 368 /** 369 * Calculates the size in bytes of the Member 370 * @return the size in bytes 371 */ 372 size_t size() const { 373 with (Type) { 374 TypeCase: 375 switch (type) { 376 foreach (E; EnumMembers!Type) { 377 static if (isHiBONBaseType(E) || isNative(E)) { 378 case E: 379 static if (E is Type.DOCUMENT) { 380 const _size = value.by!(E).size; 381 if (_size is 1) { 382 return Document.sizeKey(key) + ubyte.sizeof; 383 } 384 return Document.sizeKey(key) + LEB128.calc_size(_size) + _size; 385 } 386 else static if (E is NATIVE_DOCUMENT) { 387 const _size = value.by!(E).size; 388 return Document.sizeKey(key) + LEB128.calc_size(_size) + _size; 389 } 390 else static if (E is VER) { 391 return LEB128.calc_size(HIBON_VERSION); 392 } 393 else { 394 const v = value.by!(E); 395 return Document.sizeT(E, key, v); 396 } 397 break TypeCase; 398 } 399 } 400 default: 401 // Empty 402 } 403 assert(0, "Size of HiBON type %s is not valid"); 404 } 405 } 406 407 protected void appendList(Type E)(ref BinBuffer buffer) const 408 if (isNativeArray(E)) { 409 immutable size_index = buffer.length; 410 buffer.write(uint.init); 411 scope (exit) { 412 buffer.write(Type.NONE); 413 immutable doc_size = cast(uint)(buffer.length - size_index - uint.sizeof); 414 buffer.write(doc_size); 415 } 416 with (Type) { 417 foreach (i, h; value.by!E) { 418 const key = Text()(i); 419 //immutable key=i.to!string; 420 static if (E is NATIVE_STRING_ARRAY) { 421 Document.build(buffer, STRING, key.serialize, h); 422 } 423 else { 424 Document.buildKey(buffer, DOCUMENT, key.serialize); 425 static if (E is NATIVE_HIBON_ARRAY) { 426 h.append(buffer); 427 } 428 else static if (E is NATIVE_DOCUMENT_ARRAY) { 429 buffer.write(h.data); 430 } 431 432 else { 433 assert(0, "Support is not implemented yet"); 434 } 435 } 436 } 437 } 438 439 } 440 441 void append(ref BinBuffer buffer) const { 442 with (Type) { 443 TypeCase: 444 switch (type) { 445 static foreach (E; EnumMembers!Type) { 446 static if (isHiBONBaseType(E) || isNative(E)) { 447 case E: 448 alias T = Value.TypeT!E; 449 static if (E is DOCUMENT) { 450 Document.buildKey(buffer, E, key); 451 value.by!(E).append(buffer); 452 } 453 else static if (isNative(E)) { 454 static if (E is NATIVE_DOCUMENT) { 455 Document.buildKey(buffer, DOCUMENT, key); 456 const doc = value.by!(E); 457 buffer.write(value.by!(E).data); 458 } 459 else { 460 goto default; 461 } 462 } 463 else { 464 alias U = typeof(value.by!E()); 465 static if (is(U == const(float))) { 466 auto x = value.by!E; 467 } 468 Document.build(buffer, E, key, value.by!E); 469 } 470 break TypeCase; 471 } 472 } 473 default: 474 assert(0, "Illegal type"); 475 } 476 } 477 } 478 } 479 480 /** 481 * @return Range of members 482 */ 483 Members.Range opSlice() const { 484 return _members[]; 485 } 486 487 void opIndexAssign(ref HiBONT x, in const(char[]) key) { 488 if (!readonly && is_key_valid(key)) { 489 auto new_x = x.expropriate; 490 // auto new_member=Member(new_x, key); 491 // scope(exit) { 492 // new_member._key=null; 493 // } 494 // char[] new_key; 495 // create(new_key, key); 496 auto new_member = Member.create(new_x, key); 497 _members.insert(new_member); 498 } 499 else { 500 error++; 501 } 502 } 503 504 void opAssign(T)(T r) if ((isInputRange!T) && !isAssociativeArray!T) { 505 foreach (i, a; r.enumerate) { 506 opIndexAssign(a, i); 507 } 508 } 509 510 /** 511 * Assign and member x with the key 512 * @param x = parameter value 513 * @param key = member key 514 */ 515 void opIndexAssign(T)(T x, in const(char[]) key) if (!is(T : const(HiBONT))) { 516 if (!readonly && is_key_valid(key)) { 517 auto new_member = create!Member(x, key); 518 _members.insert(new_member); 519 } 520 else { 521 error++; 522 } 523 } 524 525 /** 526 * Assign and member x with the index 527 * @param x = parameter value 528 * @paramindex = member index 529 */ 530 void opIndexAssign(T)(T x, const size_t index) if (!is(T : const(HiBONT))) { 531 import tagion.betterC.utils.StringHelper; 532 533 if (index <= uint.max) { 534 const _key = int_to_str(index); 535 opIndexAssign(x, _key); 536 } 537 else { 538 error++; 539 } 540 } 541 542 void opIndexAssign(ref HiBONT x, const size_t index) { 543 if (index <= uint.max) { 544 Text key_text; 545 key_text(index); 546 //auto _key=Key(cast(uint)index); 547 this[key_text.serialize] = x; 548 } 549 else { 550 error++; 551 } 552 } 553 554 /** 555 * Access an member at key 556 * @param key = member key 557 * @return the Member at the key 558 * @throw if the an member with the key does not exist an HiBONException is thrown 559 */ 560 const(Member*) opIndex(in const(char[]) key) const { 561 auto m = Member(key); 562 return _members.get(&m); 563 } 564 565 /** 566 * Access an member at index 567 * @param index = member index 568 * @return the Member at the index 569 * @throw if the an member with the index does not exist an HiBONException is thrown 570 Or an std.conv.ConvException is thrown if the key is not an index 571 */ 572 const(Member*) opIndex(const size_t index) { 573 if (index <= uint.max) { 574 auto m = Member(index); 575 return _members.get(&m); 576 } 577 error++; 578 return null; 579 } 580 581 /** 582 * @param key = member key 583 * @return true if the member with the key exists 584 */ 585 bool hasMember(in const(char[]) key) const { 586 auto m = Member(key); 587 return _members.exists(&m); 588 } 589 590 /** 591 * Removes a member with name of key 592 * @param key = name of the member to be removed 593 */ 594 void remove(in const(char[]) key) { 595 auto m = Member(key); 596 _members.remove(&m); 597 } 598 599 /// 600 unittest { // remove 601 auto hibon = HiBON(); 602 hibon["d"] = 4; 603 hibon["b"] = 2; 604 hibon["c"] = 3; 605 hibon["a"] = 1; 606 607 assert(hibon.hasMember("b")); 608 hibon.remove("b"); 609 assert(!hibon.hasMember("b")); 610 } 611 612 /** 613 * @return the number of members in the HiBON 614 */ 615 size_t length() const { 616 return _members.length; 617 } 618 619 /** 620 * @return a list of the member keys 621 */ 622 KeyRange keys() const { 623 return KeyRange(&this); 624 } 625 626 protected struct KeyRange { 627 @nogc: 628 Members.Range range; 629 this(const(HiBONT*) owner) { 630 range = owner.opSlice; 631 } 632 633 ~this() { 634 range.dispose; 635 } 636 637 @property bool empty() const pure { 638 return range.empty; 639 } 640 641 @property void popFront() { 642 range.popFront; 643 } 644 645 string front() { 646 return range.front.key; 647 } 648 } 649 650 /** 651 * A list of indices 652 * @return returns false if some index is not a number; 653 */ 654 IndexRange indices() const { 655 return IndexRange(&this); 656 } 657 658 protected struct IndexRange { 659 @nogc: 660 private { 661 Members.Range range; 662 bool _error; 663 } 664 this(const(HiBONT*) owner) { 665 range = owner.opSlice; 666 } 667 668 ~this() { 669 range.dispose; 670 } 671 672 @property bool empty() const pure { 673 return range.empty; 674 } 675 676 @property void popFront() { 677 range.popFront; 678 } 679 680 uint front() { 681 uint index; 682 if (!is_index(range.front.key, index)) { 683 _error = true; 684 } 685 return index; 686 } 687 688 @property error() const pure { 689 return _error; 690 } 691 } 692 693 /** 694 * Check if the HiBON is an Array 695 * @return true if all keys is indices and are consecutive 696 */ 697 bool isArray() const { 698 auto range = indices; 699 long prev_index = -1; 700 while (!range.empty) { 701 const index = range.front; 702 if (range.error || (prev_index + 1 != index)) { 703 return false; 704 } 705 prev_index = index; 706 range.popFront; 707 } 708 return true; 709 } 710 711 int last_index() { 712 int result = -1; 713 auto range = indices; 714 while (!range.empty) { 715 const index = range.front; 716 if (!range.error) { 717 result = index; 718 } 719 range.popFront; 720 } 721 return result; 722 } 723 724 void opOpAssign(string op)(ref HiBONT cat) if (op == "~") { 725 const index = cast(uint)(last_index + 1); 726 this[index] = cat; 727 } 728 729 void opOpAssign(string op, T)(T cat) if (op == "~") { 730 const index = cast(uint)(last_index + 1); 731 this[index] = cat; 732 } 733 734 /// 735 // unittest { 736 // { 737 // auto hibon = HiBON(); 738 // assert(hibon.isArray); 739 740 // hibon["0"] = 1; 741 // assert(hibon.isArray); 742 // hibon["1"] = 2; 743 // assert(hibon.isArray); 744 // hibon["2"] = 3; 745 // assert(hibon.isArray); 746 // hibon["x"] = 3; 747 // assert(!hibon.isArray); 748 // } 749 // { 750 // auto hibon = HiBON(); 751 // hibon["1"] = 1; 752 // assert(!hibon.isArray); 753 // hibon["0"] = 2; 754 // assert(hibon.isArray); 755 // hibon["4"] = 3; 756 // assert(!hibon.isArray); 757 // hibon["3"] = 4; 758 // assert(!hibon.isArray); 759 // hibon["2"] = 7; 760 // assert(hibon.isArray); 761 // hibon["05"] = 2; 762 // assert(!hibon.isArray); 763 // } 764 // } 765 766 // unittest { 767 // struct Table { 768 // bool BOOLEAN; 769 // float FLOAT32; 770 // double FLOAT64; 771 // // BigNumberBIGINT; 772 773 // int INT32; 774 // long INT64; 775 // uint UINT32; 776 // ulong UINT64; 777 // } 778 779 // Table table; 780 // table.FLOAT32 = 1.23; 781 // table.FLOAT64 = 1.23e200; 782 // table.INT32 = -42; 783 // table.INT64 = -0x0123_3456_789A_BCDF; 784 // table.UINT32 = 42; 785 // table.UINT64 = 0x0123_3456_789A_BCDF; 786 // table.BOOLEAN = true; 787 // auto test_table = table.tupleof; 788 // //test_tabel.BIGINT = BigNumber("-1234_5678_9123_1234_5678_9123_1234_5678_9123"); 789 790 // { // empty 791 // auto hibon = HiBON(); 792 // assert(hibon.length is 0); 793 794 // assert(hibon.size is ubyte.sizeof); 795 // immutable data = hibon.serialize; 796 797 // const doc = Document(data); 798 // assert(doc.length is 0); 799 // assert(doc[].empty); 800 // } 801 802 // // Note that the keys are in alphabetic order 803 // // Because the HiBON keys must be ordered 804 // { // Single element 805 // auto hibon = HiBON(); 806 // enum pos = 1; 807 // alias A = typeof(test_table[pos]); 808 809 // static assert(is(typeof(test_table[pos]) == float)); 810 // alias M = typeof(test_table[pos]); 811 // enum key = basename!(table.tupleof[pos]); 812 813 // hibon[key] = test_table[pos]; 814 815 // assert(hibon.length is 1); 816 817 // const m = hibon[key]; 818 // assert(m.type is Type.FLOAT32); 819 // assert(m.key == key); 820 // assert(m.get!(M) == test_table[pos]); 821 // assert(m.by!(Type.FLOAT32) == test_table[pos]); 822 823 // immutable size = hibon.serialize_size; 824 // // This size of a HiBON with as single element of the type FLOAT32 825 // enum hibon_size 826 // = LEB128.calc_size(14) // Size of the object in ubytes (uint(14)) 827 // + Type.sizeof // The HiBON Type (Type.FLOAT32) 1 828 // + ubyte.sizeof // Length of the key (ubyte(7)) 2 829 // + Type.FLOAT32.stringof.length // The key text string ("FLOAT32") 9 830 // + float.sizeof // The data (float(1.23)) 13 831 // ; 832 833 // const doc_size = Document.sizeT(Type.FLOAT32, Type.FLOAT32.stringof, test_table[pos]); 834 835 // assert(size is hibon_size); 836 // assert(size is LEB128.calc_size(14) + doc_size); 837 838 // immutable data = hibon.serialize; 839 840 // const doc = Document(data); 841 842 // assert(doc.length is 1); 843 // const e = doc[key]; 844 845 // assert(e.type is Type.FLOAT32); 846 // Text key_text; 847 // assert(e.key(key_text) == key); 848 // assert(e.by!(Type.FLOAT32) == test_table[pos]); 849 850 // } 851 852 // { // HiBON Test for basic types 853 // auto hibon = HiBON(); 854 855 // string[test_table.length] keys; 856 // foreach (i, t; test_table) { 857 // enum key = basename!(table.tupleof[i]); 858 859 // hibon[key] = t; 860 // keys[i] = key; 861 // } 862 863 // size_t index; 864 // foreach (m; hibon[]) { 865 // assert(m.key == keys[index]); 866 // index++; 867 // } 868 869 // foreach (i, t; test_table) { 870 // enum key = basename!(table.tupleof[i]); 871 872 // const m = hibon[key]; 873 // assert(m.key == key); 874 // alias U = typeof(t); 875 // assert(m.get!(U) == t); 876 // } 877 878 // immutable data = hibon.serialize; 879 // const doc = Document(data); 880 881 // assert(doc.length is test_table.length); 882 883 // foreach (i, t; test_table) { 884 // enum key = basename!(table.tupleof[i]); 885 // const e = doc[key]; 886 // Text key_text; 887 // assert(e.key(key_text) == key); 888 // alias U = typeof(t); 889 // assert(e.get!(U) == t); 890 // } 891 // } 892 // } 893 894 // unittest { 895 // struct TableArray { 896 // ubyte[] BINARY; 897 // // bool[] BOOLEAN_ARRAY; 898 // // float[] FLOAT32_ARRAY; 899 // // double[]FLOAT64_ARRAY; 900 // // int[] INT32_ARRAY; 901 // // long[] INT64_ARRAY; 902 // char[] STRING; 903 // // uint[] UINT32_ARRAY; 904 // // ulong[] UINT64_ARRAY; 905 906 // } 907 908 // TableArray table_array; 909 // const(ubyte[3]) binary = [1, 2, 3]; 910 // table_array.BINARY.create(binary); 911 // // const(float[3]) float32_array=[-1.23, 3, 20e30]; 912 // // table_array.FLOAT32_ARRAY.create(float32_array); 913 // // const(double[2]) float64_array=[10.3e200, -1e-201]; 914 // // table_array.FLOAT64_ARRAY.create(float64_array); 915 // // const(int[4]) int32_array=[-11, -22, 33, 44]; 916 // // table_array.INT32_ARRAY.create(int32_array); 917 // // const(long[4]) int64_array=[0x17, 0xffff_aaaa, -1, 42]; 918 // // table_array.INT64_ARRAY.create(int64_array); 919 // // const(uint[4]) uint32_array=[11, 22, 33, 44]; 920 // // table_array.UINT32_ARRAY.create(uint32_array); 921 // // const(ulong[4]) uint64_array=[0x17, 0xffff_aaaa, 1, 42]; 922 // // table_array.UINT64_ARRAY.create(uint64_array); 923 // // const(bool[2]) boolean_array=[true, false]; 924 // // table_array.BOOLEAN_ARRAY.create(boolean_array); 925 // const(char[4]) text = "Text"; 926 // table_array.STRING.create(text); 927 928 // auto test_table_array = table_array.tupleof; 929 // scope (exit) { 930 // foreach (i, t; test_table_array) { 931 932 // .dispose(t); 933 // } 934 // } 935 936 // { // HiBON Test for basic-array types 937 // auto hibon = HiBON(); 938 939 // string[test_table_array.length] keys; 940 // foreach (i, t; test_table_array) { 941 // enum key = basename!(table_array.tupleof[i]); 942 // hibon[key] = cast(immutable) t; 943 // keys[i] = key; 944 // } 945 946 // size_t index; 947 // foreach (m; hibon[]) { 948 // assert(m.key == keys[index]); 949 // index++; 950 // } 951 952 // foreach (i, t; test_table_array) { 953 // enum key = basename!(table_array.tupleof[i]); 954 // const m = hibon[key]; 955 // assert(m.key == key); 956 // alias U = immutable(typeof(t)); 957 // assert(m.get!(U) == t); 958 // } 959 960 // immutable data = hibon.serialize; 961 // const doc = Document(data); 962 963 // assert(doc.length is test_table_array.length); 964 965 // foreach (i, t; test_table_array) { 966 // enum key = basename!(table_array.tupleof[i]); 967 // const e = doc[key]; 968 // Text key_text; 969 // assert(e.key(key_text) == key); 970 // alias U = immutable(typeof(t)); 971 // assert(e.get!(U) == t); 972 // } 973 974 // } 975 // } 976 977 // unittest { // HIBON test containg an child HiBON 978 // auto hibon = HiBON(); 979 // auto hibon_child = HiBON(); 980 // enum child_name = "child"; 981 982 // hibon["string"] = "Text"; 983 // hibon["float"] = float(1.24); 984 985 // immutable hibon_size_no_child = hibon.serialize_size; 986 // hibon_child["int32"] = 42; 987 // immutable hibon_child_size = hibon_child.serialize_size; 988 // hibon[child_name] = hibon_child; 989 990 // immutable child_key_size = Document.sizeKey(child_name); 991 // immutable hibon_size = hibon.serialize_size; 992 // assert(hibon_size is hibon_size_no_child + child_key_size + hibon_child_size); 993 994 // immutable data = hibon.serialize; 995 996 // assert(data.length is hibon_size); 997 // const doc = Document(data); 998 999 // } 1000 1001 // unittest { // Use of native Documet in HiBON 1002 // auto native_hibon = HiBON(); 1003 // native_hibon["int"] = int(42); 1004 // immutable native_data = native_hibon.serialize; 1005 // auto native_doc = Document(native_hibon.serialize); 1006 1007 // auto hibon = HiBON(); 1008 // hibon["string"] = "Text"; 1009 1010 // immutable hibon_no_native_document_size = hibon.size; 1011 // hibon["native"] = native_doc; 1012 // immutable data = hibon.serialize; 1013 // const doc = Document(data); 1014 1015 // { 1016 // const e = doc["string"]; 1017 // assert(e.type is Type.STRING); 1018 // assert(e.get!string == "Text"); 1019 // } 1020 1021 // { // Check native document 1022 // const e = doc["native"]; 1023 1024 // assert(e.type is Type.DOCUMENT); 1025 // const sub_doc = e.get!Document; 1026 // assert(sub_doc.length is 1); 1027 // assert(sub_doc.data == native_data); 1028 // const sub_e = sub_doc["int"]; 1029 // assert(sub_e.type is Type.INT32); 1030 // assert(sub_e.get!int is 42); 1031 // } 1032 // } 1033 1034 // unittest { // Document array 1035 // import std.typecons : Tuple, isTuple; 1036 1037 // auto hibon_array = HiBON(); 1038 // alias TabelDocArray = Tuple!( 1039 // int, "a", 1040 // bool, "b", 1041 // float, "c" 1042 // ); 1043 // TabelDocArray tabel_doc_array; 1044 // tabel_doc_array.a = 42; 1045 // tabel_doc_array.b = true; 1046 // tabel_doc_array.c = 42.42; 1047 1048 // foreach (i, t; tabel_doc_array) { 1049 // enum name = tabel_doc_array.fieldNames[i]; 1050 // auto local_hibon = HiBON(); 1051 // local_hibon[name] = t; 1052 // if (i < 1) { 1053 // hibon_array ~= local_hibon; 1054 // } 1055 // } 1056 1057 // auto hibon = HiBON(); 1058 // hibon["int"] = int(42); 1059 // hibon["array"] = hibon_array; 1060 1061 // immutable data = hibon.serialize; 1062 1063 // const doc = Document(data); 1064 1065 // { 1066 // assert(doc["int"].get!int is 42); 1067 // } 1068 1069 // } 1070 1071 // unittest { // Check empty/null object 1072 // { 1073 // auto hibon = HiBON(); 1074 // auto sub = HiBON(); 1075 // assert(sub.size == ubyte.sizeof); 1076 // const sub_doc = Document(sub.serialize); 1077 // hibon["a"] = sub_doc; 1078 // assert(hibon.size == Type.sizeof + ubyte.sizeof + "a".length + sub.size); 1079 1080 // } 1081 1082 // { 1083 // auto hibon = HiBON(); 1084 // auto sub = HiBON(); 1085 // assert(sub.size == ubyte.sizeof); 1086 // hibon["a"] = sub; 1087 // assert(hibon.size == Type.sizeof + ubyte.sizeof + "a".length + sub.size); 1088 // } 1089 // } 1090 1091 }