1 module upromised.promise; 2 3 import std.format : format; 4 5 interface Promise_ { 6 final protected void fatal() nothrow { 7 import std.algorithm : each; 8 import std.stdio : stderr; 9 10 try { 11 stderr.writeln("Fatal error on library"); 12 } catch(Exception e) { 13 } 14 } 15 } 16 17 void fatal(Exception e = null, string file = __FILE__, ulong line = __LINE__) nothrow { 18 import core.stdc.stdlib : abort; 19 import std.stdio : stderr; 20 try { 21 stderr.writeln("%s(%s): Fatal error".format(file, line)); 22 if (e) { 23 stderr.writeln(e); 24 } 25 } catch(Exception) { 26 abort(); 27 } 28 abort(); 29 } 30 31 template Promisify(T) { 32 static if (is(T : Promise_)) { 33 alias Promisify = T; 34 } else { 35 alias Promisify = Promise!T; 36 } 37 } 38 static assert(is(Promisify!int == Promise!int)); 39 static assert(is(Promisify!(Promise!int) == Promise!int)); 40 static assert(is(Promisify!void == Promise!void)); 41 42 auto promisify(T)(T a) nothrow { 43 static if (is(T : Promise_)) { 44 return a; 45 } else { 46 return Promise!T.resolved(a); 47 } 48 } 49 auto promisifyCall(T, U...)(T a, U b) nothrow { 50 static if (is(typeof(a(b)) == void)) { 51 try { 52 a(b); 53 return Promise!void.resolved(); 54 } catch(Exception e) { 55 return Promise!void.rejected(e); 56 } 57 } else { 58 try { 59 return promisify(a(b)); 60 } catch(Exception e) { 61 return typeof(promisify(a(b))).rejected(e); 62 } 63 } 64 } 65 66 interface Promise(T_) : Promise_ { 67 import std.typecons : Tuple; 68 69 alias T = T_; 70 71 static if (is(T == void)) { 72 alias Types = Tuple!(); 73 template Then(U) { 74 alias Then = U delegate(); 75 } 76 } else { 77 alias Types = Tuple!(T); 78 template Then(U) { 79 alias Then = U delegate(T); 80 } 81 } 82 83 struct Value { 84 this(Exception e) { 85 this.e = e; 86 } 87 88 static if (!is(T == void)) { 89 this(Exception e, T value) { 90 this.e = e; 91 this.value[0] = value; 92 } 93 } 94 95 Exception e; 96 Types value; 97 } 98 99 static if (is(T == void)) { 100 Promisify!U then(U)(U delegate() cb) nothrow { 101 return then2!U(cb); 102 } 103 } else { 104 Promisify!U then(U)(U delegate(T) cb) nothrow { 105 return then2!U(cb); 106 } 107 108 Promisify!U then(U)(U delegate() cb) nothrow { 109 return then2!U((_) => cb()); 110 } 111 } 112 113 protected Promisify!U then2(U)(Then!U cb) nothrow { 114 auto r = new DelegatePromise!(Promisify!U.T); 115 then_((value) nothrow { 116 if (value.e !is null) { 117 r.reject(value.e); 118 } else { 119 scope(failure) r.fatal(); 120 promisifyCall(cb, value.value.expand).then_((v) nothrow { 121 r.resolve(v); 122 }); 123 } 124 }); 125 return r; 126 } 127 128 Promise!void except(E,U)(U delegate(E e) cb) nothrow 129 if (is(Promisify!U.T == void) && is (E : Exception)) 130 { 131 auto r = new DelegatePromise!void; 132 then_((value) nothrow { 133 scope(failure) r.fatal(); 134 if (value.e !is null) { 135 E e = cast(E)value.e; 136 if (e !is null) { 137 promisifyCall(cb, e).then_((value) nothrow { 138 r.resolve(value); 139 }); 140 } else { 141 r.reject(value.e); 142 } 143 } else { 144 r.resolve(); 145 } 146 }); 147 return r; 148 } 149 150 auto finall(U2)(U2 delegate() cb) nothrow { 151 static if (is(Promisify!U2.T == void)) { 152 alias U = T; 153 } else { 154 alias U = U2; 155 } 156 auto r = new DelegatePromise!(Promisify!U.T); 157 then_((value) nothrow { 158 scope(failure) r.fatal(); 159 promisifyCall(cb).then_((value2) nothrow { 160 Promisify!U.Value value3; 161 value3.e = value2.e is null ? value.e : value2.e; 162 static if (is(Promisify!U2.T == void)) { 163 static if (!is(Promisify!U.T == void)) { 164 value3.value = value.value; 165 } 166 } else { 167 value3.value = value2.value; 168 } 169 170 r.resolve(value3); 171 }); 172 }); 173 return r; 174 } 175 176 Promise!T failure(U)(U delegate(Exception) cb) nothrow 177 if (is(Promisify!U.T == void)) 178 { 179 auto r = new DelegatePromise!T; 180 then_((value) nothrow { 181 if (value.e !is null) { 182 promisifyCall(cb, value.e).then_((value2) nothrow { 183 r.resolve(value); 184 }); 185 } else { 186 r.resolve(value); 187 } 188 }); 189 return r; 190 } 191 192 static if (is(T == void)) { 193 static Promise!T resolved() nothrow { 194 return resolved_(Value(null)); 195 } 196 } else { 197 static Promise!T resolved(T t) nothrow { 198 return resolved_(Value(null, t)); 199 } 200 } 201 protected static Promise!T resolved_(Value value) { 202 return new class Promise!T { 203 override void then_(void delegate(Value) nothrow cb) nothrow { 204 cb(value); 205 } 206 }; 207 } 208 209 static Promise!T rejected(Exception e) nothrow { 210 import core.runtime : Runtime; 211 if (e.info is null) { 212 try { 213 e.info = Runtime.traceHandler()(null); 214 } catch(Exception) { 215 } 216 } 217 218 return new class Promise!T { 219 override void then_(void delegate(Value) nothrow cb) nothrow { 220 cb(Value(e)); 221 } 222 }; 223 } 224 225 final Promise!void nothrow_() nothrow { 226 return except((Exception e) => .fatal(e)); 227 } 228 229 public void then_(void delegate(Value) nothrow cb) nothrow; 230 } 231 232 class DelegatePromise(T) : Promise!T { 233 bool resolved; 234 Value result; 235 void delegate(Value) nothrow[] pending; 236 237 override void then_(void delegate(Value) nothrow cb) nothrow { 238 if (resolved) { 239 cb(result); 240 } else { 241 pending ~= cb; 242 } 243 } 244 245 void resolve(Value value) nothrow { 246 scope(failure) fatal(); 247 assert(!resolved); 248 result = value; 249 resolved = true; 250 foreach(cb; pending) { 251 cb(result); 252 } 253 pending = null; 254 } 255 256 static if (is(T == void)) { 257 void resolve() nothrow { 258 resolve(Value()); 259 } 260 } else { 261 void resolve(T value) nothrow { 262 resolve(Value(null, value)); 263 } 264 } 265 void reject(Exception e) nothrow { 266 resolve(Value(e)); 267 } 268 } 269 unittest { // Multiple then 270 auto a = new DelegatePromise!int; 271 int sum = 0; 272 a.then((int a) { sum += a; }); 273 a.then((a) { sum += a; }); 274 a.resolve(2); 275 assert(sum == 4); 276 a.then((a) { sum += a; }); 277 assert(sum == 6); 278 } 279 unittest { // Void promise 280 auto a = new DelegatePromise!void; 281 bool called = false; 282 a.then(() { 283 called = true; 284 }).nothrow_(); 285 assert(!called); 286 a.resolve(); 287 assert(called); 288 } 289 290 unittest { // Void Chaining 291 auto a = new DelegatePromise!int; 292 int sum = 0; 293 a.then((a) { 294 sum += a; 295 }).then(() { 296 sum += 3; 297 }).nothrow_(); 298 assert(sum == 0); 299 a.resolve(3); 300 assert(sum == 6); 301 } 302 unittest { // Chaining 303 auto a = new DelegatePromise!int; 304 int delayValue; 305 DelegatePromise!string delayed; 306 string finalValue; 307 308 a.then((a) { 309 return a * 2; 310 }).then((a) { 311 delayed = new DelegatePromise!string; 312 delayValue = a; 313 return delayed; 314 }).then((a) { 315 finalValue = a; 316 }).nothrow_(); 317 a.resolve(1); 318 assert(delayValue == 2); 319 assert(finalValue == ""); 320 delayed.resolve("2"); 321 assert(finalValue == "2"); 322 } 323 unittest { //Exceptions 324 auto a = new DelegatePromise!int; 325 326 auto err = new Exception("yada"); 327 bool caught = false; 328 a.except((Exception e) { 329 assert(err is e); 330 caught = true; 331 }).nothrow_(); 332 assert(!caught); 333 a.reject(err); 334 assert(caught); 335 } 336 unittest { //Exception chaining 337 auto a = new DelegatePromise!int; 338 class X : Exception { 339 this() { 340 super("X"); 341 } 342 } 343 344 bool caught = false; 345 auto err = new Exception("yada"); 346 a.except((X _) { 347 assert(false); 348 }).except((Exception e) { 349 assert(e is err); 350 caught = true; 351 }).nothrow_(); 352 assert(!caught); 353 a.reject(err); 354 assert(caught); 355 } 356 unittest { 357 auto a = new DelegatePromise!int; 358 auto err = new Exception("yada"); 359 bool caught = false; 360 a.then((a) { 361 throw err; 362 }).then(() { 363 assert(false); 364 }).except((Exception e) { 365 assert(e == err); 366 caught = true; 367 }).nothrow_(); 368 assert(!caught); 369 a.resolve(2); 370 assert(caught); 371 } 372 // Finall propagates the other value 373 unittest { 374 bool called; 375 Promise!void.resolved() 376 .then(() => 2) 377 .finall(() => 3) 378 .then((a) { 379 assert(a == 3); 380 return a; 381 }).finall(() { 382 }).then((a) { 383 assert(a == 3); 384 called = true; 385 }).nothrow_(); 386 assert(called); 387 } 388 // Failure method is not called on success 389 unittest { 390 bool called; 391 Promise!int.resolved(3) 392 .failure((Exception _) { 393 assert(false); 394 }).then((a) { 395 assert(a == 3); 396 called = true; 397 }).nothrow_(); 398 assert(called); 399 } 400 // Failure method is called on error 401 unittest { 402 bool called; 403 bool called2; 404 auto err = new Exception("err"); 405 Promise!int.rejected(err) 406 .failure((Exception e) { 407 assert(e is err); 408 called = true; 409 }).except((Exception e) { 410 assert(e is err); 411 called2 = true; 412 }).nothrow_(); 413 assert(called); 414 assert(called2); 415 } 416 // Failure might be delayed 417 unittest { 418 DelegatePromise!void delay; 419 bool called2; 420 auto err = new Exception("err"); 421 Promise!int.rejected(err) 422 .failure((Exception e) { 423 assert(e is err); 424 delay = new DelegatePromise!void; 425 return delay; 426 }).except((Exception e) { 427 assert(e is err); 428 called2 = true; 429 }).nothrow_(); 430 assert(delay !is null); 431 assert(!called2); 432 delay.resolve(); 433 assert(called2); 434 } 435 interface PromiseIterator(T) { 436 struct ItValue { 437 bool eof; 438 T value; 439 } 440 Promise!ItValue next(Promise!bool done = break_); 441 442 final Promise!bool each(U)(U delegate(T) cb) nothrow 443 if (is(Promisify!U.T == void) || is(Promisify!U.T == bool)) 444 { 445 static if (is(Promisify!U.T == void)) { 446 bool delegate() boolify = () => true; 447 } else { 448 bool delegate(bool) boolify = (bool a) => a; 449 } 450 451 bool eof; 452 return do_while(() { 453 auto done = new DelegatePromise!bool; 454 return promisifyCall(&next, done).then((a) { 455 if (a.eof) { 456 done.resolve(false); 457 eof = true; 458 return break_; 459 } else { 460 return promisifyCall(cb, a.value).then(boolify).then((cont) { 461 done.resolve(cont); 462 return cont; 463 }); 464 } 465 }); 466 }).then(() => eof); 467 } 468 } 469 class DelegatePromiseIterator(T) : PromiseIterator!T { 470 import std.typecons : Tuple, tuple; 471 472 alias Value = Promise!ItValue.Value; 473 Tuple!(DelegatePromise!ItValue, Promise!bool) pending; 474 Tuple!(Promise!ItValue, DelegatePromise!bool)[] buffer; 475 476 override Promise!ItValue next(Promise!bool done) { 477 if (buffer.length > 0) { 478 auto next = buffer[0]; 479 buffer = buffer[1..$]; 480 done.then_(a => next[1].resolve(a)); 481 return next[0]; 482 } else { 483 assert(pending[0] is null); 484 pending = tuple(new DelegatePromise!ItValue, done); 485 return pending[0]; 486 } 487 } 488 489 Promise!bool resolve(T a) nothrow { 490 return resolve(Value(null, ItValue(false, a))); 491 } 492 493 Promise!bool resolve() nothrow { 494 return resolve(Value(null, ItValue(true))); 495 } 496 497 Promise!bool reject(Exception e) nothrow { 498 return resolve(Value(e)); 499 } 500 501 Promise!bool resolve(Value a) nothrow { 502 auto cb = getPending; 503 if (cb[0]) { 504 cb[0].resolve(a); 505 return cb[1]; 506 } else { 507 auto r = new DelegatePromise!bool; 508 buffer ~= tuple(Promise!ItValue.resolved_(a), r); 509 return r; 510 } 511 } 512 513 Tuple!(DelegatePromise!ItValue, Promise!bool) getPending() nothrow { 514 auto r = pending; 515 pending[0] = null; 516 return r; 517 } 518 } 519 520 unittest { //Iterator 521 DelegatePromiseIterator!int a = new DelegatePromiseIterator!int; 522 int sum = 0; 523 a.resolve(1); 524 assert(sum == 0); 525 a.each((b) { 526 sum += b; 527 return true; 528 }).then((bool) { 529 sum = 0; 530 return; 531 }).nothrow_(); 532 assert(sum == 1); 533 a.resolve(2); 534 assert(sum == 3); 535 a.resolve(); 536 assert(sum == 0); 537 } 538 unittest { //Iterator catching 539 DelegatePromiseIterator!int a = new DelegatePromiseIterator!int; 540 auto err = new Exception("yada"); 541 bool caught = false; 542 a.each((b) { 543 throw err; 544 }).except((Exception e) { 545 assert(e == err); 546 caught = true; 547 }).nothrow_(); 548 assert(!caught); 549 a.resolve(2); 550 assert(caught); 551 caught = false; 552 a.resolve(3); 553 assert(!caught); 554 a.each((b) { 555 assert(b == 3); 556 caught = true; 557 }); 558 assert(caught); 559 } 560 unittest { //Resolve done Promise 561 auto a = new DelegatePromiseIterator!int; 562 bool done = false; 563 a.resolve(2).then((a) { 564 assert(!a); 565 done = true; 566 }).nothrow_(); 567 assert(!done); 568 a.each((a) { 569 return false; 570 }); 571 assert(done); 572 done = false; 573 DelegatePromise!bool delayed; 574 a.each((a) { 575 delayed = new DelegatePromise!bool; 576 return delayed; 577 }).nothrow_(); 578 assert(!done); 579 bool done2 = false; 580 a.resolve(3).then((a) { 581 assert(a); 582 done = true; 583 }).nothrow_(); 584 a.resolve(4).then((a) { 585 assert(!a); 586 done2 = true; 587 }).nothrow_(); 588 assert(!done); 589 assert(!done2); 590 delayed.resolve(true); 591 assert(done); 592 assert(!done2); 593 delayed.resolve(false); 594 assert(done); 595 assert(done2); 596 } 597 unittest { // Rejecting iterator 598 auto a = new DelegatePromiseIterator!int; 599 bool called = false; 600 auto err = new Exception("yada"); 601 class X : Exception { 602 this() { 603 super("yada"); 604 } 605 } 606 a.each((a) { 607 assert(false); 608 }).except((X err) { 609 assert(false); 610 }).except((Exception e) { 611 assert(err is e); 612 called = true; 613 }).nothrow_(); 614 assert(!called); 615 a.reject(err); 616 assert(called); 617 } 618 unittest { //Resolved and rejected promise constructor 619 bool called = false; 620 Promise!void.resolved().then(() { 621 called = true; 622 }); 623 assert(called); 624 called = false; 625 Promise!int.resolved(3).then((a) { 626 assert(a == 3); 627 called = true; 628 }).nothrow_(); 629 assert(called); 630 called = false; 631 auto err = new Exception("yada"); 632 Promise!int.rejected(err).except((Exception e) { 633 assert(e is err); 634 called = true; 635 }).nothrow_(); 636 assert(called); 637 } 638 unittest { //Finally 639 auto a = new DelegatePromise!int; 640 auto called = [false,false,false]; 641 auto err = new Exception("yada"); 642 a.then((a) { 643 }).except((Exception e) { 644 assert(false); 645 }).finall(() { 646 called[0] = true; 647 }).then(() { 648 throw err; 649 }).finall(() { 650 called[1] = true; 651 }).except((Exception e) { 652 assert(called[1]); 653 called[2] = true; 654 assert(e is err); 655 }).nothrow_(); 656 assert(!called[0]); 657 assert(!called[1]); 658 assert(!called[2]); 659 a.resolve(1); 660 assert(called[0]); 661 assert(called[1]); 662 assert(called[2]); 663 } 664 unittest { //Finally might throw Exception 665 auto a = new DelegatePromise!int; 666 auto called = false; 667 auto err = new Exception("yada"); 668 a.finall(() { 669 throw err; 670 }).then(() { 671 assert(false); 672 }).except((Exception e) { 673 assert(e is err); 674 called = true; 675 }).nothrow_(); 676 assert(!called); 677 a.resolve(2); 678 assert(called); 679 } 680 unittest { //Finally return promise 681 auto a = new DelegatePromise!int; 682 auto called = false; 683 auto err = new Exception("yada"); 684 a.finall(() { 685 return Promise!void.rejected(err); 686 }).then(() { 687 assert(false); 688 }).except((Exception e) { 689 assert(err is e); 690 called = true; 691 }).nothrow_(); 692 assert(!called); 693 a.resolve(2); 694 assert(called); 695 } 696 unittest { //Return failed promise 697 auto a = new DelegatePromise!int; 698 auto called = false; 699 auto err = new Exception("yada"); 700 a.then((a) { 701 return Promise!void.rejected(err); 702 }).then(() { 703 assert(false); 704 }).except((Exception e) { 705 assert(err is e); 706 called = true; 707 }).nothrow_(); 708 assert(!called); 709 a.resolve(2); 710 assert(called); 711 } 712 unittest { //Finally returning a value 713 auto a = new DelegatePromise!int; 714 bool called = false; 715 a.finall(() { 716 return 2; 717 }).then((a) { 718 assert(a == 2); 719 called = true; 720 }).nothrow_(); 721 assert(!called); 722 a.resolve(0); 723 assert(called); 724 } 725 unittest { //Fail right away 726 auto a = new DelegatePromiseIterator!int; 727 auto err = new Exception("yada"); 728 bool called = false; 729 a.reject(err); 730 a.each((a) { 731 assert(false); 732 }).except((Exception e) { 733 assert(e is err); 734 called = true; 735 }).nothrow_(); 736 assert(called); 737 } 738 unittest { //EOF right away 739 auto a = new DelegatePromiseIterator!int; 740 bool called = false; 741 a.resolve(); 742 a.each((a) { 743 assert(false); 744 }).then((eof) { 745 assert(eof); 746 called = true; 747 }).nothrow_(); 748 assert(called); 749 } 750 unittest { // Ones might re-resolve right away 751 auto a = new DelegatePromiseIterator!int; 752 int calls = 0; 753 auto cont_delay = new DelegatePromise!bool; 754 755 a.resolve(0).then((cont) { 756 a.resolve(1); 757 }).nothrow_(); 758 759 a.each((b) { 760 assert(b == calls); 761 calls++; 762 763 if (b == 0) { 764 return Promise!bool.resolved(true); 765 } else { 766 return cont_delay; 767 } 768 }).then((eof) { 769 assert(eof); 770 assert(calls == 2); 771 calls++; 772 }).nothrow_(); 773 774 a.resolve(); 775 assert(calls == 2); 776 cont_delay.resolve(true); 777 } 778 // next() might throw exception 779 unittest { 780 auto err = new Exception("oi"); 781 auto x = new class PromiseIterator!int { 782 override Promise!ItValue next(Promise!bool) { 783 throw err; 784 } 785 }; 786 787 bool called = false; 788 x.each((_) { 789 assert(false); 790 }).then((_) { 791 assert(false); 792 }).except((Exception e) { 793 called = true; 794 assert(e is err); 795 }).nothrow_(); 796 assert(called); 797 } 798 private void do_while(U)(U delegate() cb, DelegatePromise!void r) nothrow { 799 promisifyCall(cb).then_((v) nothrow { 800 if (v.e) { 801 r.resolve(Promise!void.Value(v.e)); 802 return; 803 } 804 805 bool cont; 806 static if(is(Promisify!U.T == void)) { 807 cont = true; 808 } else { 809 cont = v.value[0]; 810 } 811 812 if (cont) { 813 do_while(cb, r); 814 } else { 815 r.resolve(); 816 } 817 }); 818 } 819 Promise!void do_while(U)(U delegate() cb) nothrow 820 if (is(Promisify!U.T == bool) || is(Promisify!U.T == void)) 821 { 822 auto r = new DelegatePromise!void; 823 do_while(cb, r); 824 return r; 825 } 826 static Promise!bool break_; 827 static Promise!bool continue_; 828 static this() { 829 break_ = Promise!bool.resolved(false); 830 continue_ = Promise!bool.resolved(true); 831 } 832 // do_while until return 0 833 unittest { 834 int count = 3; 835 do_while(() { 836 count--; 837 return count > 0; 838 }).nothrow_(); 839 840 assert(count == 0); 841 } 842 // do_while might be delayed 843 unittest { 844 int called = 0; 845 DelegatePromise!bool next; 846 do_while(() { 847 ++called; 848 next = new DelegatePromise!bool; 849 return next; 850 }).then(() { 851 assert(called == 2); 852 called++; 853 }).nothrow_(); 854 assert(called == 1); 855 next.resolve(true); 856 assert(called == 2); 857 next.resolve(false); 858 assert(called == 3); 859 } 860 // do_while catches all exceptions 861 unittest { 862 auto err = new Exception(""); 863 bool called; 864 do_while(() { 865 throw err; 866 }).except((Exception e) { 867 assert(e is err); 868 called = true; 869 }).nothrow_(); 870 assert(called); 871 } 872 // do_while with void loops indefinitely 873 unittest { 874 int called; 875 DelegatePromise!void next; 876 do_while(() { 877 called++; 878 next = new DelegatePromise!void; 879 return next; 880 }).nothrow_(); 881 assert(called == 1); 882 next.resolve(); 883 assert(called == 2); 884 next.resolve(); 885 assert(called == 3); 886 } 887 Promise!U race(U)(Promise!U[] ps) { 888 DelegatePromise!U result = new DelegatePromise!U; 889 foreach(p; ps) { 890 p.then_((value) nothrow { 891 if (result is null) { 892 return; 893 } 894 895 auto won = result; 896 result = null; 897 won.resolve(value); 898 }); 899 } 900 return result; 901 } 902 // race with a single promise returns the promise 903 unittest { 904 int called; 905 DelegatePromise!int wo = new DelegatePromise!int; 906 race([wo]).then((value) { 907 called = value; 908 }).nothrow_; 909 assert(called == 0); 910 wo.resolve(3); 911 assert(called == 3); 912 } 913 // race with two values returns the first called 914 unittest { 915 int called; 916 DelegatePromise!int first = new DelegatePromise!int; 917 DelegatePromise!int second = new DelegatePromise!int; 918 race([first, second]).then((value) { 919 called = value; 920 }).nothrow_; 921 assert(called == 0); 922 second.resolve(2); 923 first.resolve(1); 924 assert(called == 2); 925 } 926 // race propagates exceptions 927 unittest { 928 Exception caught; 929 Exception err = new Exception("my error"); 930 DelegatePromise!int first = new DelegatePromise!int; 931 DelegatePromise!int second = new DelegatePromise!int; 932 race([first, second]).then((value) { 933 assert(false); 934 }).except((Exception e) { 935 caught = e; 936 }).nothrow_; 937 938 assert(caught is null); 939 first.reject(err); 940 second.resolve(2); 941 assert(caught is err); 942 }