1 // Written in D programming language 2 /** 3 * Module handles functions and templates that we lazied to factor out to separate module. 4 * 5 * Function categories: 6 * <ul> 7 * <li> JSON de/serialization based on annotations </li> 8 * <li> Exception handling functions </li> 9 * <li> Cheat casting functions </li> 10 * <li> String processing functions (the only one $(B fromStringz))</li> 11 * <li> Introspecting templates that cannot be found in Phobos </li> 12 * <li> Functional styled utilities for optional values and lazy ranges</li> 13 * </ul> 14 * 15 * Copyright: © 2014 DSoftOut 16 * License: Subject to the terms of the MIT license, as written in the included LICENSE file. 17 * Authors: Zaramzan <shamyan.roman@gmail.com>, 18 * NCrashed <ncrashed@gmail.com> 19 */ 20 module util; 21 22 import std.algorithm; 23 import std.exception; 24 import std.string; 25 import std.conv; 26 import std.container; 27 import std.traits; 28 import std.typecons; 29 import std.typetuple; 30 import std.range; 31 import std.path; 32 import vibe.data.json; 33 34 enum APPNAME = "pgator"; 35 36 mixin template t_field(T, alias fieldName) 37 { 38 mixin("private "~T.stringof~" m_"~fieldName~";"); 39 40 mixin("private bool f_"~fieldName~";"); 41 42 mixin(T.stringof~" "~fieldName~"() @property { return m_"~fieldName~";}"); 43 44 mixin("private void "~fieldName~"("~T.stringof~" f) @property { m_"~fieldName~"= f; f_"~fieldName~"=true;}"); 45 } 46 47 //For deserializeFromJson 48 enum required; 49 50 //For deserializeFromJson 51 enum possible; 52 53 54 /** 55 * Deserializes from Json to type T<br> 56 * 57 * Supported only structs yet 58 * 59 * Example: 60 * ---- 61 * struct S 62 * { 63 * @required 64 * int a; //get value from Json. Throws RequiredFieldException 65 * 66 * @possible 67 * int b; //tries to get value from Json 68 * 69 * int c; //will be ignored 70 * } 71 * 72 * auto s = deserializeFromJson!S(json); 73 * ------ 74 * 75 * Authors: Zaramzan <shamyan.roman@gmail.com> 76 */ 77 T deserializeFromJson(T)(Json src) if(is(T == struct)) 78 { 79 T ret; 80 81 if (src.type != Json.Type.object) 82 { 83 throw new RequiredJsonObject("Required json object"); 84 } 85 86 void processStruct(string mem, bool isMemberOptional, Ret)(out Ret retMem, Json srcMem) 87 { 88 static if (is(Ret == Json)) 89 { 90 retMem = srcMem; 91 } 92 else 93 { 94 if (srcMem.type == Json.Type.object) 95 { 96 retMem = deserializeFromJson!Ret(srcMem); 97 } 98 else 99 { 100 // issue #96, is struct has default constructor 101 // and marked with @possible and received null 102 static if(isMemberOptional && __traits(compiles, Ret() )) 103 { 104 if(srcMem.type == Json.Type.null_) 105 { 106 retMem = Ret(); 107 } else 108 { 109 throw new RequiredFieldException(text("Field ", mem, " must be object in json: ", src)); 110 } 111 } else 112 { 113 throw new RequiredFieldException(text("Field ", mem, " must be object in json: ", src)); 114 } 115 } 116 } 117 } 118 119 void processArray(string mem, bool isMemberOptional, Ret)(out Ret retMem, Json srcMem) 120 { 121 if (srcMem.type == Json.Type.array) 122 { 123 alias ElementType!Ret ElemType; 124 125 ElemType[] arr = new ElemType[0]; 126 127 foreach(json; srcMem) 128 { 129 static if (is(ElemType == struct)) 130 { 131 arr ~= deserializeFromJson!ElemType(json); 132 } 133 else 134 { 135 static if(__traits(compiles, {ElemType t = null;})) 136 { 137 if(json.type == Json.Type.null_) 138 { 139 arr ~= null; 140 continue; 141 } 142 } 143 arr ~= json.to!ElemType; 144 } 145 } 146 147 retMem = arr; 148 } 149 else 150 { 151 // array could be a null for @possible. issue #96 152 static if(isMemberOptional) 153 { 154 if(srcMem.type == Json.Type.null_) 155 { 156 retMem = null; 157 } else 158 { 159 throw new RequiredFieldException(text("Field ", mem, " must be array in json: ", src)); 160 } 161 } else 162 { 163 throw new RequiredFieldException(text("Field ", mem, " must be array in json: ", src)); 164 } 165 } 166 } 167 168 foreach(mem; __traits(allMembers, T)) 169 { 170 alias getMemberType!(T, mem) MemberType; 171 enum isMemberRequired = isRequired!(mem, T); 172 enum isMemberOptional = isOptional!(mem, T); 173 174 enum srcMem = "src."~mem; 175 enum retMem = "ret."~mem; 176 177 static if (isMemberRequired || isMemberOptional) 178 { 179 if (mixin(srcMem).type != Json.Type.undefined) 180 { 181 static if(is(MemberType == struct)) 182 { 183 processStruct!(mem, isMemberOptional)(mixin(retMem), mixin(srcMem)); 184 } 185 else static if(isArray!MemberType && !isSomeString!MemberType) 186 { 187 processArray!(mem, isMemberOptional)(mixin(retMem), mixin(srcMem)); 188 } 189 else 190 { 191 mixin(retMem) = mixin(srcMem).to!MemberType(); 192 } 193 } 194 else static if (isMemberRequired) 195 { 196 throw new RequiredFieldException(text("Field ", mem, " required in json: ", src)); 197 } 198 } 199 200 } 201 202 return ret; 203 } 204 unittest // issue #96 205 { 206 struct A 207 { 208 @possible 209 ubyte[] a; 210 } 211 212 auto a = A(null); 213 assert(deserializeFromJson!A(serializeToJson(a)) == a); 214 215 struct B 216 { 217 @possible 218 A a; 219 } 220 221 auto b = B(A(null)); 222 assert(deserializeFromJson!B(serializeToJson(b)) == b); 223 } 224 225 /** 226 * Serializes struct with $(B @required) attributes fields to Json <br> 227 * 228 * Example 229 * ------ 230 * struct S 231 * { 232 * @required 233 * int a = 1; //will be used 234 * 235 * @possible 236 * int b = 2; //will be ignored 237 * 238 * int c; //will be ignored 239 * } 240 * 241 * writeln(serializeRequiredToJson(S())); // { "a":1 } 242 * ------ 243 */ 244 Json serializeRequiredToJson(T)(T val) 245 { 246 static assert (is(T == struct), "Need struct type, not "~T.stringof); 247 248 Json ret = Json.emptyObject; 249 250 foreach(mem; __traits(allMembers, T)) 251 { 252 static if (isRequired!(mem, T)) 253 { 254 alias getMemberType!(T, mem) MemType; 255 256 alias vibe.data.json.serializeToJson vibeSer; 257 258 static if (is(MemType == struct)) 259 { 260 ret[mem] = serializeRequiredToJson!MemType(mixin("val."~mem)); 261 } 262 else static if (isArray!MemType) 263 { 264 alias ElementType!MemType EType; 265 static if (is(EType == struct)) 266 { 267 auto j1 = Json.emptyArray; 268 269 foreach(elem; mixin("val."~mem)) 270 { 271 j1 ~= serializeRequiredToJson(elem); 272 } 273 274 ret[mem] = j1; 275 } 276 else 277 { 278 ret[mem] = vibeSer(mixin("val."~mem)); 279 } 280 } 281 else 282 { 283 ret[mem] = vibeSer(mixin("val."~mem)); 284 } 285 } 286 } 287 288 return ret; 289 } 290 291 private bool isRequired(alias mem, T)() 292 { 293 bool flag = false; 294 foreach(attr;__traits(getAttributes, mixin("T."~mem))) 295 { 296 static if (is(attr == required)) 297 { 298 flag = true; 299 break; 300 } 301 } 302 303 return flag; 304 } 305 306 private bool isOptional(alias mem, T)() 307 { 308 bool flag = false; 309 foreach(attr;__traits(getAttributes, mixin("T."~mem))) 310 { 311 static if (is(attr == possible)) 312 { 313 flag = true; 314 break; 315 } 316 } 317 318 return flag; 319 } 320 321 class RequiredFieldException:Exception 322 { 323 this(in string msg) 324 { 325 super(msg); 326 } 327 } 328 329 class RequiredJsonObject:Exception 330 { 331 this(in string msg) 332 { 333 super(msg); 334 } 335 } 336 337 /** 338 * Tries to call function. On exception throws Ex, otherwise return func() result 339 * 340 * Authors: Zaramzan <shamyan.roman@gmail.com> 341 */ 342 template tryEx(Ex, alias func) 343 { 344 static assert(isSomeFunction!func, "func must be some function"); 345 static assert(is(Ex:Exception), "Ex must be Exception"); 346 347 auto wrapper(TP...)(TP params) 348 { 349 try 350 { 351 return func(params); 352 } 353 catch(Exception ex) 354 { 355 throw new Ex(ex.msg, ex.file, ex.line); 356 } 357 } 358 359 alias wrapper tryEx; 360 } 361 362 /** 363 * Tries to evaluate par. On exception throws Ex, otherwise return par 364 * 365 * Authors: Zaramzan <shamyan.roman@gmail.com> 366 */ 367 T tryEx(Ex, T)(lazy T par) 368 { 369 static assert(is(Ex:Exception), "Ex must be Exception"); 370 371 try 372 { 373 return par; 374 } 375 catch(Exception ex) 376 { 377 throw new Ex(ex.msg, ex.file, ex.line); 378 } 379 } 380 381 /** 382 * cast to shared type T 383 * 384 * Warning: 385 * Don't use this, if you want send object to another thread. It just dirty hack. 386 */ 387 template toShared(T) 388 { 389 private alias Unqual!T P; 390 391 shared(P) toShared(T par) 392 { 393 return cast(shared P) cast(P) par; 394 } 395 } 396 397 /// cast to unqual type T 398 template toUnqual(T) 399 { 400 private alias Unqual!T P; 401 402 P toUnqual(T par) 403 { 404 return cast(P) par; 405 } 406 } 407 408 version(unittest) 409 { 410 bool thrower() 411 { 412 throw new Exception("Exception"); 413 } 414 415 class TestException: Exception 416 { 417 @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) 418 { 419 super(msg, file, line, next); 420 } 421 } 422 } 423 424 unittest 425 { 426 import std.exception; 427 428 assertThrown!TestException(tryEx!TestException(thrower())); 429 } 430 431 static if (__VERSION__ < 2066) { // from phobos 2.066-b1 432 import std.c.string; 433 434 /++ 435 Returns a D-style array of $(D char) given a zero-terminated C-style string. 436 The returned array will retain the same type qualifiers as the input. 437 438 $(RED Important Note:) The returned array is a slice of the original buffer. 439 The original data is not changed and not copied. 440 +/ 441 442 inout(char)[] fromStringz(inout(char)* cString) @system pure { 443 return cString ? cString[0 .. strlen(cString)] : null; 444 } 445 446 /// 447 @system pure unittest 448 { 449 assert(fromStringz(null) == null); 450 assert(fromStringz("foo") == "foo"); 451 } 452 } else { 453 public import std.string: fromStringz; 454 } 455 456 /// getMemberType 457 /** 458 * Retrieves member type with $(D name) of class $(D Class). If member is agregate 459 * type declaration or simply doesn't exist, retrieves no type. You can check it with 460 * $(D is) operator. 461 * 462 * Example: 463 * ----------- 464 * class A 465 * { 466 * int aField; 467 * string b; 468 * bool c; 469 * 470 * class B {} 471 * struct C {} 472 * union D {} 473 * interface E {} 474 * } 475 * 476 * static assert(is(getMemberType!(A, "aField") == int)); 477 * static assert(is(getMemberType!(A, "b") == string)); 478 * static assert(is(getMemberType!(A, "c") == bool)); 479 * 480 * static assert(!is(getMemberType!(A, "B"))); 481 * static assert(!is(getMemberType!(A, "C"))); 482 * static assert(!is(getMemberType!(A, "D"))); 483 * static assert(!is(getMemberType!(A, "E"))); 484 * ----------- 485 */ 486 template getMemberType(Class, string name) 487 { 488 static if(hasMember!(Class, name)) 489 alias typeof(__traits(getMember, Class, name)) getMemberType; 490 } 491 492 unittest 493 { 494 class A 495 { 496 int a; 497 string b; 498 bool c; 499 500 class B {} 501 struct C {} 502 union D {} 503 interface E {} 504 } 505 506 static assert(is(getMemberType!(A, "a") == int)); 507 static assert(is(getMemberType!(A, "b") == string)); 508 static assert(is(getMemberType!(A, "c") == bool)); 509 510 static assert(!is(getMemberType!(A, "B"))); 511 static assert(!is(getMemberType!(A, "C"))); 512 static assert(!is(getMemberType!(A, "D"))); 513 static assert(!is(getMemberType!(A, "E"))); 514 } 515 516 /// FieldNameTuple 517 /** 518 * Retrieves names of all class/struct/union $(D Class) fields excluding technical ones like this, Monitor. 519 * 520 * Example: 521 * --------- 522 * class A 523 * { 524 * int aField; 525 * 526 * void func1() {} 527 * static void func2() {} 528 * 529 * string b; 530 * 531 * final func3() {} 532 * abstract void func4(); 533 * 534 * bool c; 535 * } 536 * 537 * static assert(FieldNameTuple!A == ["aField","b","c"]); 538 * --------- 539 */ 540 template FieldNameTuple(Class) 541 { 542 template removeFuncs(funcs...) 543 { 544 static if(funcs.length > 0) 545 { 546 // if member is class/struct/interface declaration second part getMemberType returns no type 547 static if( is(getMemberType!(Class, funcs[0]) == function) || 548 !is(getMemberType!(Class, funcs[0])) || 549 funcs[0] == "this" || funcs[0] == "Monitor" || funcs[0] == "__ctor" || 550 funcs[0] == "opEquals" || funcs[0] == "opCmp" || funcs[0] == "opAssign") 551 { 552 enum removeFuncs = removeFuncs!(funcs[1..$]); 553 } 554 else 555 enum removeFuncs = [funcs[0]]~removeFuncs!(funcs[1..$]); 556 } 557 else 558 enum removeFuncs = []; 559 } 560 561 enum temp = removeFuncs!(__traits(allMembers, Class)); 562 static if(temp.length > 0) 563 enum FieldNameTuple = temp[0..$-1]; 564 else 565 enum FieldNameTuple = []; 566 } 567 568 // ddoc example 569 /*unittest 570 { 571 class A 572 { 573 int a; 574 575 void func1() {} 576 static void func2() {} 577 578 string b; 579 580 final func3() {} 581 abstract void func4(); 582 583 bool c; 584 } 585 586 static assert(FieldNameTuple!A == ["a","b","c"]); 587 } 588 unittest 589 { 590 class P 591 { 592 void foo() {} 593 594 real p; 595 } 596 597 class A : P 598 { 599 int aField; 600 601 void func1() {} 602 static void func2() {} 603 604 string b; 605 606 final void func3() {} 607 abstract void func4(); 608 609 bool c; 610 611 void function(int,int) da; 612 void delegate(int, int) db; 613 614 class B {} 615 B mB; 616 617 struct C {} 618 C mC; 619 620 interface D {} 621 } 622 623 static assert(FieldNameTuple!A == ["aField","b","c","da","db","mB","mC","p"]); 624 static assert(is(getMemberType!(A, "aField") == int)); 625 static assert(is(getMemberType!(A, "b") == string)); 626 static assert(is(getMemberType!(A, "c") == bool)); 627 628 struct S1 629 { 630 int a; 631 bool b; 632 633 void foo() {} 634 635 real c; 636 } 637 638 static assert(FieldNameTuple!S1 == ["a","b","c"]); 639 640 union S2 641 { 642 size_t index; 643 void* pointer; 644 } 645 646 static assert(FieldNameTuple!S2 == ["index", "pointer"]); 647 648 class S3 649 { 650 651 } 652 static assert(FieldNameTuple!S3 == []); 653 654 // Properties detected as field. To fix. 655 struct S4 656 { 657 @property S4 dup() 658 { 659 return S4(); 660 } 661 } 662 static assert(FieldNameTuple!S4 == ["dup"]); 663 }*/ 664 665 /// Removes one element from the list 666 /** 667 * NEVER use while iterating the $(B list). 668 */ 669 void removeOne(T)(ref DList!T list, T elem) 670 { 671 auto toRemove = list[].find(elem).take(1); 672 list.linearRemove(toRemove); 673 } 674 675 /** 676 * Struct-wrapper to handle result of computations, 677 * that can fail. 678 * 679 * Example: 680 * --------- 681 * class A {} 682 * 683 * auto a = new A(); 684 * auto ma = Maybe!A(a); 685 * auto mb = Maybe!A(null); 686 * 687 * assert(!ma.isNothing); 688 * assert(mb.isNothing); 689 * 690 * assert(ma.get == a); 691 * assertThrown!Error(mb.get); 692 * 693 * bool ncase = false, jcase = false; 694 * ma.map(() {ncase = true;}, (v) {jcase = true;}); 695 * assert(jcase && !ncase); 696 * 697 * ncase = jcase = false; 698 * mb.map(() {ncase = true;}, (v) {jcase = true;}); 699 * assert(!jcase && ncase); 700 * --------- 701 */ 702 struct Maybe(T) 703 if(is(T == class) || is(T == interface) 704 || isPointer!T || isArray!T) 705 { 706 private T value; 707 708 /// Alias to stored type 709 alias T StoredType; 710 711 /** 712 * Constructing Maybe from $(B value). 713 * If pointer is $(B null) methods: $(B isNothing) returns true and 714 * $(B get) throws Error. 715 */ 716 this(T value) pure 717 { 718 this.value = value; 719 } 720 721 /** 722 * Constructing empty Maybe. 723 * If Maybe is created with the method, it is considred empty 724 * and $(B isNothing) returns false. 725 */ 726 static Maybe!T nothing() 727 { 728 return Maybe!T(null); 729 } 730 731 /// Returns true if stored value is null 732 bool isNothing() const 733 { 734 return value is null; 735 } 736 737 /** 738 * Unwrap value from Maybe. 739 * If stored value is $(B null), Error is thrown. 740 */ 741 T get() 742 { 743 assert(value !is null, "Stored reference is null!"); 744 return value; 745 } 746 747 /** 748 * Unwrap value from Maybe. 749 * If stored value is $(B null), Error is thrown. 750 */ 751 const(T) get() const 752 { 753 assert(value !is null, "Stored reference is null!"); 754 return value; 755 } 756 757 /** 758 * If struct holds $(B null), then $(B nothingCase) result 759 * is returned. If struct holds not $(B null) value, then 760 * $(justCase) result is returned. $(B justCase) is fed 761 * with unwrapped value. 762 */ 763 U map(U)(U delegate() nothingCase, U delegate(T) justCase) 764 { 765 return isNothing ? nothingCase() : justCase(value); 766 } 767 768 /** 769 * If struct holds $(B null), then $(B nothingCase) result 770 * is returned. If struct holds not $(B null) value, then 771 * $(justCase) result is returned. $(B justCase) is fed 772 * with unwrapped value. 773 */ 774 U map(U)(U delegate() nothingCase, U delegate(const T) justCase) const 775 { 776 return isNothing ? nothingCase() : justCase(value); 777 } 778 } 779 780 unittest 781 { 782 class A {} 783 784 auto a = new A(); 785 auto ma = Maybe!A(a); 786 auto mb = Maybe!A(null); 787 788 assert(!ma.isNothing); 789 assert(mb.isNothing); 790 791 assert(ma.get == a); 792 assertThrown!Error(mb.get); 793 794 bool ncase = false, jcase = false; 795 ma.map(() {ncase = true;}, (v) {jcase = true;}); 796 assert(jcase && !ncase); 797 798 ncase = jcase = false; 799 mb.map(() {ncase = true;}, (v) {jcase = true;}); 800 assert(!jcase && ncase); 801 } 802 803 /** 804 * Struct-wrapper to handle result of computations, 805 * that can fail. 806 * 807 * Example: 808 * --------- 809 * struct A {} 810 * 811 * auto ma = Maybe!A(A()); 812 * auto mb = Maybe!A.nothing; 813 * 814 * assert(!ma.isNothing); 815 * assert(mb.isNothing); 816 * 817 * assert(ma.get == A()); 818 * assertThrown!Error(mb.get); 819 * 820 * bool ncase = false, jcase = false; 821 * ma.map(() {ncase = true;}, (v) {jcase = true;}); 822 * assert(jcase && !ncase); 823 * 824 * ncase = jcase = false; 825 * mb.map(() {ncase = true;}, (v) {jcase = true;}); 826 * assert(!jcase && ncase); 827 * --------- 828 */ 829 struct Maybe(T) 830 if(is(T == struct) || isAssociativeArray!T || isBasicType!T) 831 { 832 private bool empty; 833 private T value; 834 835 /// Alias to stored type 836 alias T StoredType; 837 838 /** 839 * Constructing empty Maybe. 840 * If Maybe is created with the method, it is considred empty 841 * and $(B isNothing) returns false. 842 */ 843 static Maybe!T nothing() 844 { 845 Maybe!T ret; 846 ret.empty = true; 847 return ret; 848 } 849 850 /** 851 * Constructing Maybe from $(B value). 852 * If Maybe is created with the constructor, it is considered non empty 853 * and $(B isNothing) returns false. 854 */ 855 this(T value) pure 856 { 857 this.value = value; 858 empty = false; 859 } 860 861 /// Returns true if stored value is null 862 bool isNothing() const 863 { 864 return empty; 865 } 866 867 /** 868 * Unwrap value from Maybe. 869 * If the Maybe is empty, Error is thrown. 870 */ 871 T get() 872 { 873 assert(!empty, "Stored value is null!"); 874 return value; 875 } 876 877 /** 878 * Unwrap value from Maybe. 879 * If the Maybe is empty, Error is thrown. 880 */ 881 const(T) get() const 882 { 883 assert(!empty, "Stored value is null!"); 884 return value; 885 } 886 887 /** 888 * If struct holds $(B null), then $(B nothingCase) result 889 * is returned. If struct holds not $(B null) value, then 890 * $(justCase) result is returned. $(B justCase) is fed 891 * with unwrapped value. 892 */ 893 U map(U)(U delegate() nothingCase, U delegate(T) justCase) 894 { 895 return isNothing ? nothingCase() : justCase(value); 896 } 897 898 /** 899 * If struct holds $(B null), then $(B nothingCase) result 900 * is returned. If struct holds not $(B null) value, then 901 * $(justCase) result is returned. $(B justCase) is fed 902 * with unwrapped value. 903 */ 904 U map(U)(U delegate() nothingCase, U delegate(const T) justCase) const 905 { 906 return isNothing ? nothingCase() : justCase(value); 907 } 908 } 909 910 unittest 911 { 912 struct A {} 913 914 auto ma = Maybe!A(A()); 915 auto mb = Maybe!A.nothing; 916 917 assert(!ma.isNothing); 918 assert(mb.isNothing); 919 920 assert(ma.get == A()); 921 assertThrown!Error(mb.get); 922 923 bool ncase = false, jcase = false; 924 ma.map(() {ncase = true;}, (v) {jcase = true;}); 925 assert(jcase && !ncase); 926 927 ncase = jcase = false; 928 mb.map(() {ncase = true;}, (v) {jcase = true;}); 929 assert(!jcase && ncase); 930 } 931 932 /** 933 * Transforms delegate into lazy range. Generation is stopped, when 934 * $(B genfunc) returns $(B Maybe!T.nothing). 935 * 936 * Example: 937 * -------- 938 * assert( (() => Maybe!int(1)).generator.take(10).equal(1.repeat.take(10)) ); 939 * assert( (() => Maybe!int.nothing).generator.empty); 940 * assert( (() 941 * { 942 * static size_t i = 0; 943 * return i++ < 10 ? Maybe!int(1) : Maybe!int.nothing; 944 * } 945 * ).generator.equal(1.repeat.take(10))); 946 * 947 * class A {} 948 * auto a = new A(); 949 * 950 * assert( (() => Maybe!A(a)).generator.take(10).equal(a.repeat.take(10)) ); 951 * assert( (() => Maybe!A.nothing).generator.empty); 952 * assert( (() 953 * { 954 * static size_t i = 0; 955 * return i++ < 10 ? Maybe!A(a) : Maybe!A.nothing; 956 * } 957 * ).generator.equal(a.repeat.take(10))); 958 * -------- 959 */ 960 auto generator(T)(Maybe!T delegate() genfunc) 961 { 962 struct Sequencer 963 { 964 private Maybe!T currvalue; 965 966 T front() 967 { 968 assert(!currvalue.isNothing, "Generator range is empty!"); 969 return currvalue.get; 970 } 971 972 bool empty() 973 { 974 return currvalue.isNothing; 975 } 976 977 void popFront() 978 { 979 currvalue = genfunc(); 980 } 981 } 982 static assert(isInputRange!Sequencer); 983 984 auto s = Sequencer(); 985 s.popFront; 986 return s; 987 } 988 unittest 989 { 990 assert( (() => Maybe!int(1)).generator.take(10).equal(1.repeat.take(10)) ); 991 assert( (() => Maybe!int.nothing).generator.empty); 992 assert( (() 993 { 994 static size_t i = 0; 995 return i++ < 10 ? Maybe!int(1) : Maybe!int.nothing; 996 } 997 ).generator.equal(1.repeat.take(10))); 998 999 class A {} 1000 auto a = new A(); 1001 1002 assert( (() => Maybe!A(a)).generator.take(10).equal(a.repeat.take(10)) ); 1003 assert( (() => Maybe!A.nothing).generator.empty); 1004 assert( (() 1005 { 1006 static size_t i = 0; 1007 return i++ < 10 ? Maybe!A(a) : Maybe!A.nothing; 1008 } 1009 ).generator.equal(a.repeat.take(10))); 1010 } 1011 1012 private template TypesOf(T...) 1013 { 1014 static if(T.length == 1) 1015 alias TypesOf = typeof(T[0]); 1016 else 1017 alias TypesOf = TypeTuple!(typeof(T[0]), TypesOf!(T[1..$])); 1018 } 1019 1020 /** 1021 * Allows to fast retreiving results from functions that returns a tuple. 1022 */ 1023 @property void tie(T...)(Tuple!(TypesOf!T) t) 1024 { 1025 foreach(i, ref var; T) 1026 { 1027 T[i] = t[i]; 1028 } 1029 } 1030 /// Example 1031 unittest 1032 { 1033 Tuple!(int, string) foo() 1034 { 1035 return tuple(1, "a"); 1036 } 1037 1038 int x; 1039 string y; 1040 1041 tie!(x,y) = foo(); 1042 assert(x == 1 && y == "a"); 1043 }