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 }