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 foreach(attr;__traits(getAttributes, mixin("T."~mem))) 294 { 295 static if (is(attr == required)) 296 { 297 return true; 298 } 299 } 300 301 return false; 302 } 303 304 private bool isOptional(alias mem, T)() 305 { 306 foreach(attr;__traits(getAttributes, mixin("T."~mem))) 307 { 308 static if (is(attr == possible)) 309 { 310 return true; 311 } 312 } 313 314 return false; 315 } 316 317 class RequiredFieldException:Exception 318 { 319 this(in string msg) 320 { 321 super(msg); 322 } 323 } 324 325 class RequiredJsonObject:Exception 326 { 327 this(in string msg) 328 { 329 super(msg); 330 } 331 } 332 333 /** 334 * Tries to call function. On exception throws Ex, otherwise return func() result 335 * 336 * Authors: Zaramzan <shamyan.roman@gmail.com> 337 */ 338 template tryEx(Ex, alias func) 339 { 340 static assert(isSomeFunction!func, "func must be some function"); 341 static assert(is(Ex:Exception), "Ex must be Exception"); 342 343 auto wrapper(TP...)(TP params) 344 { 345 try 346 { 347 return func(params); 348 } 349 catch(Exception ex) 350 { 351 throw new Ex(ex.msg, ex.file, ex.line); 352 } 353 } 354 355 alias wrapper tryEx; 356 } 357 358 /** 359 * Tries to evaluate par. On exception throws Ex, otherwise return par 360 * 361 * Authors: Zaramzan <shamyan.roman@gmail.com> 362 */ 363 T tryEx(Ex, T)(lazy T par) 364 { 365 static assert(is(Ex:Exception), "Ex must be Exception"); 366 367 try 368 { 369 return par; 370 } 371 catch(Exception ex) 372 { 373 throw new Ex(ex.msg, ex.file, ex.line); 374 } 375 } 376 377 /** 378 * cast to shared type T 379 * 380 * Warning: 381 * Don't use this, if you want send object to another thread. It just dirty hack. 382 */ 383 template toShared(T) 384 { 385 private alias Unqual!T P; 386 387 shared(P) toShared(T par) 388 { 389 return cast(shared P) cast(P) par; 390 } 391 } 392 393 /// cast to unqual type T 394 template toUnqual(T) 395 { 396 private alias Unqual!T P; 397 398 P toUnqual(T par) 399 { 400 return cast(P) par; 401 } 402 } 403 404 version(unittest) 405 { 406 bool thrower() 407 { 408 throw new Exception("Exception"); 409 } 410 411 class TestException: Exception 412 { 413 @safe pure nothrow this(string msg, string file = __FILE__, size_t line = __LINE__, Throwable next = null) 414 { 415 super(msg, file, line, next); 416 } 417 } 418 } 419 420 unittest 421 { 422 import std.exception; 423 424 assertThrown!TestException(tryEx!TestException(thrower())); 425 } 426 427 static if (__VERSION__ < 2066) { // from phobos 2.066-b1 428 import std.c.string; 429 430 /++ 431 Returns a D-style array of $(D char) given a zero-terminated C-style string. 432 The returned array will retain the same type qualifiers as the input. 433 434 $(RED Important Note:) The returned array is a slice of the original buffer. 435 The original data is not changed and not copied. 436 +/ 437 438 inout(char)[] fromStringz(inout(char)* cString) @system pure { 439 return cString ? cString[0 .. strlen(cString)] : null; 440 } 441 442 /// 443 @system pure unittest 444 { 445 assert(fromStringz(null) == null); 446 assert(fromStringz("foo") == "foo"); 447 } 448 } else { 449 public import std.string: fromStringz; 450 } 451 452 /// getMemberType 453 /** 454 * Retrieves member type with $(D name) of class $(D Class). If member is agregate 455 * type declaration or simply doesn't exist, retrieves no type. You can check it with 456 * $(D is) operator. 457 * 458 * Example: 459 * ----------- 460 * class A 461 * { 462 * int aField; 463 * string b; 464 * bool c; 465 * 466 * class B {} 467 * struct C {} 468 * union D {} 469 * interface E {} 470 * } 471 * 472 * static assert(is(getMemberType!(A, "aField") == int)); 473 * static assert(is(getMemberType!(A, "b") == string)); 474 * static assert(is(getMemberType!(A, "c") == bool)); 475 * 476 * static assert(!is(getMemberType!(A, "B"))); 477 * static assert(!is(getMemberType!(A, "C"))); 478 * static assert(!is(getMemberType!(A, "D"))); 479 * static assert(!is(getMemberType!(A, "E"))); 480 * ----------- 481 */ 482 template getMemberType(Class, string name) 483 { 484 static if(hasMember!(Class, name)) 485 alias typeof(__traits(getMember, Class, name)) getMemberType; 486 } 487 488 unittest 489 { 490 class A 491 { 492 int a; 493 string b; 494 bool c; 495 496 class B {} 497 struct C {} 498 union D {} 499 interface E {} 500 } 501 502 static assert(is(getMemberType!(A, "a") == int)); 503 static assert(is(getMemberType!(A, "b") == string)); 504 static assert(is(getMemberType!(A, "c") == bool)); 505 506 static assert(!is(getMemberType!(A, "B"))); 507 static assert(!is(getMemberType!(A, "C"))); 508 static assert(!is(getMemberType!(A, "D"))); 509 static assert(!is(getMemberType!(A, "E"))); 510 } 511 512 /// FieldNameTuple 513 /** 514 * Retrieves names of all class/struct/union $(D Class) fields excluding technical ones like this, Monitor. 515 * 516 * Example: 517 * --------- 518 * class A 519 * { 520 * int aField; 521 * 522 * void func1() {} 523 * static void func2() {} 524 * 525 * string b; 526 * 527 * final func3() {} 528 * abstract void func4(); 529 * 530 * bool c; 531 * } 532 * 533 * static assert(FieldNameTuple!A == ["aField","b","c"]); 534 * --------- 535 */ 536 template FieldNameTuple(Class) 537 { 538 template removeFuncs(funcs...) 539 { 540 static if(funcs.length > 0) 541 { 542 // if member is class/struct/interface declaration second part getMemberType returns no type 543 static if( is(getMemberType!(Class, funcs[0]) == function) || 544 !is(getMemberType!(Class, funcs[0])) || 545 funcs[0] == "this" || funcs[0] == "Monitor" || funcs[0] == "__ctor" || 546 funcs[0] == "opEquals" || funcs[0] == "opCmp" || funcs[0] == "opAssign") 547 { 548 enum removeFuncs = removeFuncs!(funcs[1..$]); 549 } 550 else 551 enum removeFuncs = [funcs[0]]~removeFuncs!(funcs[1..$]); 552 } 553 else 554 enum removeFuncs = []; 555 } 556 557 enum temp = removeFuncs!(__traits(allMembers, Class)); 558 static if(temp.length > 0) 559 enum FieldNameTuple = temp[0..$-1]; 560 else 561 enum FieldNameTuple = []; 562 } 563 564 // ddoc example 565 unittest 566 { 567 class A 568 { 569 int a; 570 571 void func1() {} 572 static void func2() {} 573 574 string b; 575 576 final func3() {} 577 abstract void func4(); 578 579 bool c; 580 } 581 582 static assert(FieldNameTuple!A == ["a","b","c"]); 583 } 584 unittest 585 { 586 class P 587 { 588 void foo() {} 589 590 real p; 591 } 592 593 class A : P 594 { 595 int aField; 596 597 void func1() {} 598 static void func2() {} 599 600 string b; 601 602 final void func3() {} 603 abstract void func4(); 604 605 bool c; 606 607 void function(int,int) da; 608 void delegate(int, int) db; 609 610 class B {} 611 B mB; 612 613 struct C {} 614 C mC; 615 616 interface D {} 617 } 618 619 static assert(FieldNameTuple!A == ["aField","b","c","da","db","mB","mC","p"]); 620 static assert(is(getMemberType!(A, "aField") == int)); 621 static assert(is(getMemberType!(A, "b") == string)); 622 static assert(is(getMemberType!(A, "c") == bool)); 623 624 struct S1 625 { 626 int a; 627 bool b; 628 629 void foo() {} 630 631 real c; 632 } 633 634 static assert(FieldNameTuple!S1 == ["a","b","c"]); 635 636 union S2 637 { 638 size_t index; 639 void* pointer; 640 } 641 642 static assert(FieldNameTuple!S2 == ["index", "pointer"]); 643 644 class S3 645 { 646 647 } 648 static assert(FieldNameTuple!S3 == []); 649 650 // Properties detected as field. To fix. 651 struct S4 652 { 653 @property S4 dup() 654 { 655 return S4(); 656 } 657 } 658 static assert(FieldNameTuple!S4 == ["dup"]); 659 } 660 661 /// Removes one element from the list 662 /** 663 * NEVER use while iterating the $(B list). 664 */ 665 void removeOne(T)(ref DList!T list, T elem) 666 { 667 auto toRemove = list[].find(elem).take(1); 668 list.linearRemove(toRemove); 669 } 670 671 /** 672 * Struct-wrapper to handle result of computations, 673 * that can fail. 674 * 675 * Example: 676 * --------- 677 * class A {} 678 * 679 * auto a = new A(); 680 * auto ma = Maybe!A(a); 681 * auto mb = Maybe!A(null); 682 * 683 * assert(!ma.isNothing); 684 * assert(mb.isNothing); 685 * 686 * assert(ma.get == a); 687 * assertThrown!Error(mb.get); 688 * 689 * bool ncase = false, jcase = false; 690 * ma.map(() {ncase = true;}, (v) {jcase = true;}); 691 * assert(jcase && !ncase); 692 * 693 * ncase = jcase = false; 694 * mb.map(() {ncase = true;}, (v) {jcase = true;}); 695 * assert(!jcase && ncase); 696 * --------- 697 */ 698 struct Maybe(T) 699 if(is(T == class) || is(T == interface) 700 || isPointer!T || isArray!T) 701 { 702 private T value; 703 704 /// Alias to stored type 705 alias T StoredType; 706 707 /** 708 * Constructing Maybe from $(B value). 709 * If pointer is $(B null) methods: $(B isNothing) returns true and 710 * $(B get) throws Error. 711 */ 712 this(T value) pure 713 { 714 this.value = value; 715 } 716 717 /** 718 * Constructing empty Maybe. 719 * If Maybe is created with the method, it is considred empty 720 * and $(B isNothing) returns false. 721 */ 722 static Maybe!T nothing() 723 { 724 return Maybe!T(null); 725 } 726 727 /// Returns true if stored value is null 728 bool isNothing() const 729 { 730 return value is null; 731 } 732 733 /** 734 * Unwrap value from Maybe. 735 * If stored value is $(B null), Error is thrown. 736 */ 737 T get() 738 { 739 assert(value !is null, "Stored reference is null!"); 740 return value; 741 } 742 743 /** 744 * Unwrap value from Maybe. 745 * If stored value is $(B null), Error is thrown. 746 */ 747 const(T) get() const 748 { 749 assert(value !is null, "Stored reference is null!"); 750 return value; 751 } 752 753 /** 754 * If struct holds $(B null), then $(B nothingCase) result 755 * is returned. If struct holds not $(B null) value, then 756 * $(justCase) result is returned. $(B justCase) is fed 757 * with unwrapped value. 758 */ 759 U map(U)(U delegate() nothingCase, U delegate(T) justCase) 760 { 761 return isNothing ? nothingCase() : justCase(value); 762 } 763 764 /** 765 * If struct holds $(B null), then $(B nothingCase) result 766 * is returned. If struct holds not $(B null) value, then 767 * $(justCase) result is returned. $(B justCase) is fed 768 * with unwrapped value. 769 */ 770 U map(U)(U delegate() nothingCase, U delegate(const T) justCase) const 771 { 772 return isNothing ? nothingCase() : justCase(value); 773 } 774 } 775 776 unittest 777 { 778 class A {} 779 780 auto a = new A(); 781 auto ma = Maybe!A(a); 782 auto mb = Maybe!A(null); 783 784 assert(!ma.isNothing); 785 assert(mb.isNothing); 786 787 assert(ma.get == a); 788 assertThrown!Error(mb.get); 789 790 bool ncase = false, jcase = false; 791 ma.map(() {ncase = true;}, (v) {jcase = true;}); 792 assert(jcase && !ncase); 793 794 ncase = jcase = false; 795 mb.map(() {ncase = true;}, (v) {jcase = true;}); 796 assert(!jcase && ncase); 797 } 798 799 /** 800 * Struct-wrapper to handle result of computations, 801 * that can fail. 802 * 803 * Example: 804 * --------- 805 * struct A {} 806 * 807 * auto ma = Maybe!A(A()); 808 * auto mb = Maybe!A.nothing; 809 * 810 * assert(!ma.isNothing); 811 * assert(mb.isNothing); 812 * 813 * assert(ma.get == A()); 814 * assertThrown!Error(mb.get); 815 * 816 * bool ncase = false, jcase = false; 817 * ma.map(() {ncase = true;}, (v) {jcase = true;}); 818 * assert(jcase && !ncase); 819 * 820 * ncase = jcase = false; 821 * mb.map(() {ncase = true;}, (v) {jcase = true;}); 822 * assert(!jcase && ncase); 823 * --------- 824 */ 825 struct Maybe(T) 826 if(is(T == struct) || isAssociativeArray!T || isBasicType!T) 827 { 828 private bool empty; 829 private T value; 830 831 /// Alias to stored type 832 alias T StoredType; 833 834 /** 835 * Constructing empty Maybe. 836 * If Maybe is created with the method, it is considred empty 837 * and $(B isNothing) returns false. 838 */ 839 static Maybe!T nothing() 840 { 841 Maybe!T ret; 842 ret.empty = true; 843 return ret; 844 } 845 846 /** 847 * Constructing Maybe from $(B value). 848 * If Maybe is created with the constructor, it is considered non empty 849 * and $(B isNothing) returns false. 850 */ 851 this(T value) pure 852 { 853 this.value = value; 854 empty = false; 855 } 856 857 /// Returns true if stored value is null 858 bool isNothing() const 859 { 860 return empty; 861 } 862 863 /** 864 * Unwrap value from Maybe. 865 * If the Maybe is empty, Error is thrown. 866 */ 867 T get() 868 { 869 assert(!empty, "Stored value is null!"); 870 return value; 871 } 872 873 /** 874 * Unwrap value from Maybe. 875 * If the Maybe is empty, Error is thrown. 876 */ 877 const(T) get() const 878 { 879 assert(!empty, "Stored value is null!"); 880 return value; 881 } 882 883 /** 884 * If struct holds $(B null), then $(B nothingCase) result 885 * is returned. If struct holds not $(B null) value, then 886 * $(justCase) result is returned. $(B justCase) is fed 887 * with unwrapped value. 888 */ 889 U map(U)(U delegate() nothingCase, U delegate(T) justCase) 890 { 891 return isNothing ? nothingCase() : justCase(value); 892 } 893 894 /** 895 * If struct holds $(B null), then $(B nothingCase) result 896 * is returned. If struct holds not $(B null) value, then 897 * $(justCase) result is returned. $(B justCase) is fed 898 * with unwrapped value. 899 */ 900 U map(U)(U delegate() nothingCase, U delegate(const T) justCase) const 901 { 902 return isNothing ? nothingCase() : justCase(value); 903 } 904 } 905 906 unittest 907 { 908 struct A {} 909 910 auto ma = Maybe!A(A()); 911 auto mb = Maybe!A.nothing; 912 913 assert(!ma.isNothing); 914 assert(mb.isNothing); 915 916 assert(ma.get == A()); 917 assertThrown!Error(mb.get); 918 919 bool ncase = false, jcase = false; 920 ma.map(() {ncase = true;}, (v) {jcase = true;}); 921 assert(jcase && !ncase); 922 923 ncase = jcase = false; 924 mb.map(() {ncase = true;}, (v) {jcase = true;}); 925 assert(!jcase && ncase); 926 } 927 928 /** 929 * Transforms delegate into lazy range. Generation is stopped, when 930 * $(B genfunc) returns $(B Maybe!T.nothing). 931 * 932 * Example: 933 * -------- 934 * assert( (() => Maybe!int(1)).generator.take(10).equal(1.repeat.take(10)) ); 935 * assert( (() => Maybe!int.nothing).generator.empty); 936 * assert( (() 937 * { 938 * static size_t i = 0; 939 * return i++ < 10 ? Maybe!int(1) : Maybe!int.nothing; 940 * } 941 * ).generator.equal(1.repeat.take(10))); 942 * 943 * class A {} 944 * auto a = new A(); 945 * 946 * assert( (() => Maybe!A(a)).generator.take(10).equal(a.repeat.take(10)) ); 947 * assert( (() => Maybe!A.nothing).generator.empty); 948 * assert( (() 949 * { 950 * static size_t i = 0; 951 * return i++ < 10 ? Maybe!A(a) : Maybe!A.nothing; 952 * } 953 * ).generator.equal(a.repeat.take(10))); 954 * -------- 955 */ 956 auto generator(T)(Maybe!T delegate() genfunc) 957 { 958 struct Sequencer 959 { 960 private Maybe!T currvalue; 961 962 T front() 963 { 964 assert(!currvalue.isNothing, "Generator range is empty!"); 965 return currvalue.get; 966 } 967 968 bool empty() 969 { 970 return currvalue.isNothing; 971 } 972 973 void popFront() 974 { 975 currvalue = genfunc(); 976 } 977 } 978 static assert(isInputRange!Sequencer); 979 980 auto s = Sequencer(); 981 s.popFront; 982 return s; 983 } 984 unittest 985 { 986 assert( (() => Maybe!int(1)).generator.take(10).equal(1.repeat.take(10)) ); 987 assert( (() => Maybe!int.nothing).generator.empty); 988 assert( (() 989 { 990 static size_t i = 0; 991 return i++ < 10 ? Maybe!int(1) : Maybe!int.nothing; 992 } 993 ).generator.equal(1.repeat.take(10))); 994 995 class A {} 996 auto a = new A(); 997 998 assert( (() => Maybe!A(a)).generator.take(10).equal(a.repeat.take(10)) ); 999 assert( (() => Maybe!A.nothing).generator.empty); 1000 assert( (() 1001 { 1002 static size_t i = 0; 1003 return i++ < 10 ? Maybe!A(a) : Maybe!A.nothing; 1004 } 1005 ).generator.equal(a.repeat.take(10))); 1006 } 1007 1008 private template TypesOf(T...) 1009 { 1010 static if(T.length == 1) 1011 alias TypesOf = typeof(T[0]); 1012 else 1013 alias TypesOf = TypeTuple!(typeof(T[0]), TypesOf!(T[1..$])); 1014 } 1015 1016 /** 1017 * Allows to fast retreiving results from functions that returns a tuple. 1018 */ 1019 @property void tie(T...)(Tuple!(TypesOf!T) t) 1020 { 1021 foreach(i, ref var; T) 1022 { 1023 T[i] = t[i]; 1024 } 1025 } 1026 /// Example 1027 unittest 1028 { 1029 Tuple!(int, string) foo() 1030 { 1031 return tuple(1, "a"); 1032 } 1033 1034 int x; 1035 string y; 1036 1037 tie!(x,y) = foo(); 1038 assert(x == 1 && y == "a"); 1039 }