1 module sbin.ut; 2 3 import std.array : appender; 4 5 import sbin.type; 6 import sbin.exception; 7 import sbin.serialize; 8 import sbin.deserialize; 9 10 version (unittest) import std.algorithm : equal; 11 12 @safe unittest 13 { 14 const a = 123; 15 assert(a.sbinSerialize.sbinDeserialize!int == a); 16 } 17 18 @safe unittest 19 { 20 enum V { v } 21 const a = V.v; 22 static assert(is(V == enum)); 23 static assert(is(EnumNumType!V == ubyte)); 24 const s = a.sbinSerialize; 25 assert (s.length == 1); 26 assert(s.sbinDeserialize!V == a); 27 } 28 29 @safe unittest 30 { 31 const a = 123; 32 auto as = a.sbinSerialize; 33 int x; 34 sbinDeserialize(as, x); 35 assert(a == x); 36 } 37 38 @safe unittest 39 { 40 auto s = "hello world"; 41 assert(equal(s.sbinSerialize.sbinDeserialize!string, s)); 42 } 43 44 @safe unittest 45 { 46 immutable(int[]) a = [1,2,3,2,3,2,1]; 47 assert(a.sbinSerialize.sbinDeserialize!(int[]) == a); 48 } 49 50 @safe unittest 51 { 52 const int[5] a = [1,2,3,2,3]; 53 assert(a.sbinSerialize.sbinDeserialize!(typeof(a)) == a); 54 } 55 56 @safe unittest 57 { 58 enum Color 59 { 60 black = "#000000", 61 red = "#ff0000", 62 green = "#00ff00", 63 blue = "#0000ff", 64 white = "#ffffff" 65 } 66 67 enum Level { low, medium, high } 68 69 struct Foo 70 { 71 ulong a; 72 float b, c; 73 ushort d; 74 string str; 75 Color color; 76 @sbinSkip int local = 42; 77 } 78 79 const foo1 = Foo(10, 3.14, 2.17, 8, "s1", Color.red); 80 81 // a b c d 82 const foo1Size = ulong.sizeof + float.sizeof * 2 + ushort.sizeof + 83 // str color 84 (1 + foo1.str.length) + ubyte.sizeof; // 1 is length data because length < 127 (vluint pack) 85 86 // color is ubyte because [EnumMembers!Color].length < ubyte.max 87 88 const foo1Data = foo1.sbinSerialize; 89 90 assert(foo1Data.length == foo1Size); 91 assert(foo1Data.sbinDeserialize!Foo == foo1); 92 93 const foo2 = Foo(2, 2.22, 2.22, 2, "str2", Color.green); 94 95 const foo2Size = ulong.sizeof + float.sizeof * 2 + ushort.sizeof + 96 (1 + foo2.str.length) + ubyte.sizeof; 97 98 const foo2Data = foo2.sbinSerialize; 99 100 assert(foo2Data.length == foo2Size); 101 assert(foo2Data.sbinDeserialize!Foo == foo2); 102 103 struct Bar 104 { 105 ulong a; 106 float b; 107 Level level; 108 Foo[] foos; 109 } 110 111 auto bar = Bar(123, 3.14, Level.high, [ foo1, foo2 ]); 112 113 // a b level 114 const barSize = ulong.sizeof + float.sizeof + ubyte.sizeof + 115 // foos 116 (1 + foo1Size + foo2Size); 117 118 assert(bar.sbinSerialize.length == barSize); 119 120 auto data = [ 121 bar, 122 Bar(23, 123 31.4, Level.high, 124 [ 125 Foo(10, .11, .22, 50, "1one1"), 126 Foo(20, .13, .25, 70, "2two2", Color.black), 127 Foo(30, .15, .28, 30, "3three3", Color.white), 128 ] 129 ), 130 ]; 131 132 auto sdata = data.sbinSerialize; 133 assert( equal(sdata.sbinDeserialize!(Bar[]), data)); 134 data[0].foos[1].d = 12_345; 135 assert(!equal(sdata.sbinDeserialize!(Bar[]), data)); 136 } 137 138 @safe unittest 139 { 140 struct S 141 { 142 @sbinSkip int* p; 143 } 144 145 auto s1 = S(new int(42)); 146 147 auto data = s1.sbinSerialize; 148 assert(data.length == 0); 149 150 auto s2 = data.sbinDeserialize!S; 151 assert(s2.p == null); 152 } 153 154 @safe unittest 155 { 156 static void foo(int a=123, string b="hello") 157 { assert(a==123); assert(b=="hello"); } 158 159 auto a = ParameterDefaults!foo; 160 161 import std.typecons : tuple; 162 const sa = tuple(a).sbinSerialize; 163 164 Parameters!foo b; 165 b = sa.sbinDeserialize!(typeof(tuple(b))); 166 assert(a == b); 167 foo(b); 168 169 a[0] = 234; 170 a[1] = "okda"; 171 auto sn = tuple(a).sbinSerialize; 172 173 sn.sbinDeserialize(b); 174 175 assert(b[0] == 234); 176 assert(b[1] == "okda"); 177 } 178 179 @safe unittest 180 { 181 auto a = [1,2,3,4]; 182 auto as = a.sbinSerialize; 183 auto as_tr = as[0..$-3]; 184 assertThrown!SBinDeserializeEmptyRangeException(as_tr.sbinDeserialize!(typeof(a))); 185 } 186 187 @safe unittest 188 { 189 auto a = [1,2,3,4]; 190 auto as = a.sbinSerialize; 191 auto as_tr = as ~ as; 192 assertThrown!SBinDeserializeException(as_tr.sbinDeserialize!(typeof(a))); 193 } 194 195 @safe unittest 196 { 197 auto a = ["hello" : 123, "ok" : 43]; 198 auto as = a.sbinSerialize; 199 200 auto b = as.sbinDeserialize!(typeof(a)); 201 assert(b["hello"] == 123); 202 assert(b["ok"] == 43); 203 } 204 205 unittest 206 { 207 static struct X 208 { 209 string[int] one; 210 int[string] two; 211 } 212 213 auto a = X([3: "hello", 8: "abc"], ["ok": 1, "no": 2]); 214 auto b = X([8: "abc", 15: "ololo"], ["zb": 10]); 215 216 const as = a.sbinSerialize; 217 const bs = b.sbinSerialize; 218 219 auto c = as.sbinDeserialize!X; 220 221 import std.algorithm : sort; 222 assert(equal(sort(a.one.keys.dup), sort(c.one.keys.dup))); 223 assert(equal(sort(a.one.values.dup), sort(c.one.values.dup))); 224 225 bs.sbinDeserialize(c); 226 227 assert(equal(sort(b.one.keys.dup), sort(c.one.keys.dup))); 228 assert(equal(sort(b.one.values.dup), sort(c.one.values.dup))); 229 } 230 231 @safe unittest 232 { 233 enum T { one, two, three } 234 T[] a; 235 with(T) a = [one, two, three, two, three, two, one]; 236 const as = a.sbinSerialize; 237 238 auto b = as.sbinDeserialize!(typeof(a)); 239 assert(equal(a, b)); 240 } 241 242 @safe unittest 243 { 244 enum T { one="one", two="2", three="III" } 245 T[] a; 246 with(T) a = [one, two, three, two, three, two, one]; 247 const as = a.sbinSerialize; 248 249 assert(as.length == 7 + 1); 250 251 auto b = as.sbinDeserialize!(typeof(a)); 252 assert(equal(a, b)); 253 } 254 255 @safe unittest 256 { 257 const int ai = 543; 258 auto as = "hello"; 259 260 import std.typecons : tuple; 261 auto buf = sbinSerialize(tuple(ai, as)); 262 263 int bi; 264 string bs; 265 sbinDeserialize(buf, bi, bs); 266 267 assert(ai == bi); 268 assert(bs == as); 269 } 270 271 @safe unittest 272 { 273 const int ai = 543; 274 auto as = "hello"; 275 276 auto buf = appender!(ubyte[]); 277 sbinSerialize(buf, ai, as); 278 279 int bi; 280 string bs; 281 sbinDeserialize(buf.data, bi, bs); 282 283 assert(ai == bi); 284 assert(bs == as); 285 } 286 287 @safe unittest 288 { 289 static struct ImplaceAppender(Arr) 290 { 291 Arr _data; 292 size_t cur; 293 294 this(Arr arr) { _data = arr; } 295 296 @safe @nogc pure nothrow 297 { 298 void put(E)(E e) 299 if (is(typeof(_data[0] = e))) 300 { 301 _data[cur] = e; 302 cur++; 303 } 304 305 bool filled() const @property 306 { return cur == data.length; } 307 308 inout(Arr) data() inout { return _data[0..cur]; } 309 310 void clear() { cur = 0; } 311 } 312 } 313 314 alias Buffer = ImplaceAppender!(ubyte[]); 315 316 static assert(isOutputRange!(Buffer, ubyte)); 317 318 enum State 319 { 320 one = "ONE", 321 two = "TWO", 322 three = "THREE", 323 } 324 325 struct Cell 326 { 327 ulong id; 328 float volt, temp; 329 ushort soc, soh; 330 string strData; 331 State state; 332 } 333 334 struct Line 335 { 336 ulong id; 337 float volt, curr; 338 Cell[] cells; 339 } 340 341 auto lines = [ 342 Line(123, 343 3.14, 2.17, 344 [ 345 Cell(1, 1.1, 2.2, 5, 8, "one", State.one), 346 Cell(2, 1.3, 2.5, 7, 9, "two", State.two), 347 Cell(3, 1.5, 2.8, 3, 7, "three", State.three), 348 ] 349 ), 350 Line(23, 351 31.4, 21.7, 352 [ 353 Cell(10, .11, .22, 50, 80, "1one1", State.two), 354 Cell(20, .13, .25, 70, 90, "2two2", State.three), 355 Cell(30, .15, .28, 30, 70, "3three3", State.one), 356 ] 357 ), 358 ]; 359 360 ubyte[300] bdata; 361 auto buffer = Buffer(bdata[]); 362 363 () @nogc { buffer.sbinSerialize(lines); }(); 364 365 assert(equal(buffer.data.sbinDeserialize!(typeof(lines)), lines)); 366 } 367 368 @safe unittest 369 { 370 static bool ser, deser; 371 static struct Foo 372 { 373 ulong id; 374 ulong sbinCustomRepr() const @property 375 { 376 ser = true; 377 return id; 378 } 379 static Foo sbinFromCustomRepr(ulong v) 380 { 381 deser = true; 382 return Foo(v); 383 } 384 } 385 386 auto foo = Foo(12); 387 388 assert(foo.sbinSerialize.sbinDeserialize!Foo == foo); 389 assert(ser); 390 assert(deser); 391 } 392 393 @safe unittest 394 { 395 static bool ser, deser; 396 static class Foo 397 { 398 ulong id; 399 this(ulong v) @safe { id = v; } 400 ulong sbinCustomRepr() const @safe 401 { 402 ser = true; 403 return id; 404 } 405 static Foo sbinFromCustomRepr()(auto ref const ulong v) @safe 406 { 407 deser = true; 408 return new Foo(v); 409 } 410 } 411 412 auto foo = new Foo(12); 413 414 assert(foo.sbinSerialize.sbinDeserialize!Foo.id == 12); 415 assert(ser); 416 assert(deser); 417 418 Foo[] fooArr; 419 foreach (i; 0 .. 10) 420 fooArr ~= new Foo(i); 421 422 import std.algorithm : map; 423 424 auto fooArr2 = fooArr.sbinSerialize.sbinDeserialize!(Foo[]); 425 assert(equal(fooArr.map!"a.id", fooArr2.map!"a.id")); 426 } 427 428 @safe unittest 429 { 430 // for classes need 431 // T sbinCustomRepr() const 432 // static Foo sbinCustomDeserialize(T repr) 433 static class Foo 434 { 435 ulong id; 436 this(ulong v) { id = v; } 437 } 438 439 auto foo = new Foo(12); 440 441 static assert(!is(typeof(foo.sbinSerialize))); 442 static assert(!is(typeof(foo.sbinSerialize.sbinDeserialize!Foo.id))); 443 } 444 445 @safe unittest 446 { 447 import std.bitmanip : bitfields; 448 449 static struct Foo 450 { 451 mixin(bitfields!( 452 bool, "a", 1, 453 bool, "b", 1, 454 ubyte, "c", 4, 455 ubyte, "d", 2 456 )); 457 } 458 459 static assert(Foo.sizeof == 1); 460 461 Foo foo; 462 foo.a = true; 463 foo.b = false; 464 foo.c = 9; 465 foo.d = 3; 466 467 assert(foo.a); 468 assert(foo.b == false); 469 assert(foo.c == 9); 470 assert(foo.d == 3); 471 472 auto sfoo = foo.sbinSerialize; 473 474 assert(sfoo.length == 1); 475 476 auto bar = sfoo.sbinDeserialize!Foo; 477 478 assert(bar.a); 479 assert(bar.b == false); 480 assert(bar.c == 9); 481 assert(bar.d == 3); 482 483 assert(foo == bar); 484 } 485 486 @safe unittest 487 { 488 struct Foo 489 { 490 ubyte[] a, b; 491 } 492 493 auto arr = cast(ubyte[])[1,2,3,4,5,6]; 494 const foo = Foo(arr, arr[0..2]); 495 assert (foo.a.ptr == foo.b.ptr); 496 497 const foo2 = foo.sbinSerialize.sbinDeserialize!Foo; 498 assert(foo == foo2); 499 assert(foo.a.ptr != foo2.a.ptr); 500 assert(foo.b.ptr != foo2.b.ptr); 501 assert(foo2.a.ptr != foo2.b.ptr); 502 } 503 504 unittest 505 { 506 struct Foo { void[] a; } 507 auto foo = Foo("hello".dup); 508 auto foo2 = foo.sbinSerialize.sbinDeserialize!Foo; 509 assert(equal(cast(ubyte[])foo.a, cast(ubyte[])foo2.a)); 510 } 511 512 unittest 513 { 514 struct Foo { void[5] a; } 515 auto foo = Foo(cast(void[5])"hello"); 516 auto foo2 = foo.sbinSerialize.sbinDeserialize!Foo; 517 assert(equal(cast(ubyte[])foo.a, cast(ubyte[])foo2.a)); 518 } 519 520 unittest 521 { 522 struct Foo { void[] a; void[5] b; } 523 auto foo = Foo("hello".dup, cast(void[5])"world"); 524 auto foo2 = foo.sbinSerialize.sbinDeserialize!Foo; 525 assert(equal(cast(ubyte[])foo.a, cast(ubyte[])foo2.a)); 526 assert(equal(cast(ubyte[])foo.b, cast(ubyte[])foo2.b)); 527 } 528 529 unittest 530 { 531 import std.variant : Algebraic; 532 533 struct Foo 534 { 535 Algebraic!(int, float, string) data; 536 this(int a) { data = a; } 537 this(float a) { data = a; } 538 this(string a) { data = a; } 539 } 540 541 auto foo = Foo(12); 542 static assert(!__traits(compiles, foo.sbinSerialize.sbinDeserialize!Foo)); 543 } 544 545 @safe unittest 546 { 547 import std.algorithm : max; 548 549 union Union 550 { 551 float fval; 552 byte ival; 553 } 554 555 static assert(Union.init.sizeof == max(float.sizeof, byte.sizeof)); 556 557 Union u; 558 u.ival = 114; 559 assert (u.ival == 114); 560 561 const su = u.sbinSerialize.sbinDeserialize!Union; 562 assert (su.ival == 114); 563 } 564 565 unittest 566 { 567 auto buf = appender!(ubyte[]); 568 569 struct Foo1 { void[] a; void[5] b; } 570 auto foo1 = Foo1("hello".dup, cast(void[5])"world"); 571 572 sbinSerialize(buf, foo1); 573 574 static struct Foo2 575 { 576 import std.bitmanip : bitfields; 577 mixin(bitfields!( 578 bool, "a", 1, 579 bool, "b", 1, 580 ubyte, "c", 4, 581 ubyte, "d", 2 582 )); 583 } 584 585 Foo2 foo2; 586 foo2.a = true; 587 foo2.b = false; 588 foo2.c = 9; 589 foo2.d = 3; 590 591 sbinSerialize(buf, foo2); 592 593 auto data = buf.data; 594 595 auto dsfoo1 = sbinDeserializePart!Foo1(data); 596 const dsfoo2 = sbinDeserializePart!Foo2(data); 597 598 assert (data.empty); 599 600 assert(equal(cast(ubyte[])foo1.a, cast(ubyte[])dsfoo1.a)); 601 assert(equal(cast(ubyte[])foo1.b, cast(ubyte[])dsfoo1.b)); 602 assert(dsfoo2.a); 603 assert(dsfoo2.b == false); 604 assert(dsfoo2.c == 9); 605 assert(dsfoo2.d == 3); 606 } 607 608 @safe unittest 609 { 610 enum Label { good, bad } 611 static struct Pos { int x, y; } 612 static struct Point { Pos position; Label label; } 613 614 Point[2] val = [ 615 Point(Pos(3,7), Label.good), 616 Point(Pos(9,5), Label.bad), 617 ]; 618 auto data = sbinSerialize(val); 619 620 assert(data.length == 18); 621 622 import std.algorithm : canFind; 623 624 { 625 bool throws; 626 try auto dsv = sbinDeserialize!(Point[2])(data[0..$-3]); 627 catch (SBinDeserializeEmptyRangeException e) 628 { 629 throws = true; 630 assert (e.msg.canFind("root.elem[1].position.y.byte[2]:int 2/4"), e.msg); 631 } 632 assert (throws); 633 } 634 { 635 bool throws; 636 try const dsv = sbinDeserialize!(Point[2])(data[0..$-1]); 637 catch (SBinDeserializeEmptyRangeException e) 638 { 639 throws = true; 640 assert (e.msg.canFind("root.elem[1].label.byte[0]:Label 0/1"), e.msg); 641 } 642 assert (throws); 643 } 644 { 645 bool throws; 646 try const dsv = sbinDeserialize!(Point[2])(data[0..$/2+1]); 647 catch (SBinDeserializeEmptyRangeException e) 648 { 649 throws = true; 650 assert (e.msg.canFind("root.elem[1].position.x.byte[1]:int 1/4"), e.msg); 651 } 652 assert (throws); 653 } 654 { 655 bool throws; 656 try const dsv = sbinDeserialize!(Point[2])(data[0..$/2-1]); 657 catch (SBinDeserializeEmptyRangeException e) 658 { 659 throws = true; 660 assert (e.msg.canFind("root.elem[0].label.byte[0]:Label 0/1"), e.msg); 661 } 662 assert (throws); 663 } 664 } 665 666 @safe unittest 667 { 668 ushort[] val = [10,12,14,15]; 669 670 auto data = sbinSerialize(val); 671 672 assert(data.length == 9); 673 674 import std.algorithm : canFind; 675 676 { 677 bool throws; 678 try const dsv = sbinDeserialize!(ushort[])(data[0..$-3]); 679 catch (SBinDeserializeEmptyRangeException e) 680 { 681 throws = true; 682 assert (e.msg.canFind("root.elem[2].byte[1]:ushort 1/2"), e.msg); 683 } 684 assert (throws); 685 } 686 687 { 688 bool throws; 689 try const dsv = sbinDeserialize!(ushort[])(data[0..0]); 690 catch (SBinDeserializeEmptyRangeException e) 691 { 692 throws = true; 693 assert (e.msg.canFind("root.length:vluint 0/10"), e.msg); 694 } 695 assert (throws); 696 } 697 } 698 699 @safe unittest 700 { 701 short[] value; 702 auto rng = sbinSerialize(value); 703 assert (rng.length == 1); 704 assert (rng[0] == 0); 705 706 assert (sbinDeserialize!(short[])(rng).length == 0); 707 } 708 709 @safe unittest 710 { 711 vlint[] value = [vlint(1),vlint(2),vlint(3)]; 712 auto rng = sbinSerialize(value); 713 assert (rng.length == 4); 714 assert (rng[0] == 3); 715 assert (rng[1] == 2); 716 assert (rng[2] == 4); 717 assert (rng[3] == 6); 718 719 assert (value == sbinDeserialize!(typeof(value))(rng)); 720 } 721 722 @safe unittest 723 { 724 vlint[] value = [vlint(1),vlint(-130),vlint(3)]; 725 auto rng = sbinSerialize(value); 726 assert (rng.length == 5); 727 assert (rng[0] == 3); 728 assert (rng[1] == 2); 729 //assert (rng[2] == 4); 730 assert (rng[4] == 6); 731 732 assert (value == sbinDeserialize!(typeof(value))(rng)); 733 } 734 735 @safe unittest 736 { 737 vluint[] value = [vluint(1),vluint(2),vluint(3)]; 738 auto rng = sbinSerialize(value); 739 assert (rng.length == 4); 740 assert (rng[0] == 3); 741 assert (rng[1] == 1); 742 assert (rng[2] == 2); 743 assert (rng[3] == 3); 744 745 assert (value == sbinDeserialize!(typeof(value))(rng)); 746 } 747 748 unittest 749 { 750 import std.bitmanip; 751 import std.random : uniform; 752 import std.range : iota; 753 import std.algorithm : map; 754 import std.array : array; 755 756 BitArray b = iota(273).map!(a=>cast(bool)uniform!"[]"(0,1)).array; 757 758 static struct BitArrayWrap 759 { 760 BitArray arr; 761 this(BitArray a) { arr = a; } 762 this(Repr r) { arr = BitArray(r.data, r.bitcount); } 763 764 static struct Repr 765 { 766 vluint bitcount; 767 void[] data; 768 } 769 770 Repr sbinCustomRepr() @property const 771 { return Repr(vluint(arr.length), cast(void[])arr.dup); } 772 773 static BitArrayWrap sbinFromCustomRepr(Repr r) 774 { return BitArrayWrap(r); } 775 } 776 777 const t1 = sbinDeserialize!BitArrayWrap(sbinSerialize(BitArrayWrap(b))).arr; 778 779 assert (b == t1); 780 781 static struct BitArrayWrap2 782 { 783 vluint bitcount; 784 void[] data; 785 786 this(BitArray ba) { bitcount = ba.length; data = cast(void[])ba; } 787 } 788 789 const pft2 = sbinDeserialize!BitArrayWrap2(sbinSerialize(BitArrayWrap2(b))); 790 791 const t2 = BitArray(pft2.data.dup, pft2.bitcount); 792 793 assert (b == t2); 794 795 import std.datetime; 796 797 static struct RH 798 { 799 enum sbinReprHandler; 800 static: 801 static struct BAW3 { vluint bc; void[] data; } 802 BAW3 repr(const BitArray ba) { return BAW3(vluint(ba.length), cast(void[])ba.dup); } 803 BitArray fromRepr(BAW3 w) { return BitArray(w.data.dup, w.bc); } 804 805 long repr(const SysTime t) { return t.toUTC.stdTime; } 806 SysTime fromRepr(long r) { return SysTime(r, UTC()); } 807 } 808 809 auto t3 = sbinDeserialize!(RH, BitArray)(sbinSerialize!RH(b)); 810 811 assert (b == t3); 812 813 struct Foo 814 { 815 string name; 816 BitArray data; 817 SysTime tm; 818 } 819 820 auto foo = Foo("hello", b, Clock.currTime); 821 822 const foo_bytes = sbinSerialize!RH(foo); 823 824 auto foo2 = sbinDeserialize!(RH, Foo)(foo_bytes); 825 826 assert (foo.name == foo2.name); 827 assert (foo.data == foo2.data); 828 assert (foo.tm == foo2.tm); 829 assert (foo == foo2); 830 }