1 module sbylib.engine.promise; 2 3 import std; 4 import core.thread; 5 import sbylib.event; 6 7 class Promise(T) { 8 9 alias Type = T; 10 11 private VoidEvent task; 12 private Exception e; 13 14 static if (!is(T == void)) { 15 private Nullable!T result; 16 } 17 18 static if (is(T == void)) { 19 this(void delegate(void delegate()) f) { 20 this.task = when(Frame).then({}); 21 f({ this.task.kill(); }); 22 } 23 } else { 24 this(void delegate(void delegate(T)) f) { 25 this.task = when(Frame).then({}); 26 f((T t) { 27 result = t.nullable; 28 // writeln("result = ", t); 29 this.task.kill(); 30 }); 31 } 32 } 33 34 this(Args...)(T delegate(Args) f, Args args) { 35 this.task = when(Frame).once({ 36 this.exec(f, args); 37 }); 38 } 39 40 this(Args...)(T delegate(Args) f, Promise!Args parent) { 41 this.task = when(Frame).then({ 42 // writeln("po"); 43 if (parent.finished is false) return; 44 static if (is(P.Type == void)) { 45 this.exec(f); 46 } else { 47 // for avoid execution on parent's error 48 if (parent.result.isNull is false) { 49 this.exec(f, parent.result.get()); 50 } 51 } 52 this.task.kill(); 53 }); 54 } 55 56 this(Args...)(Promise!T delegate(Args) f, Promise!Args parent) { 57 this.task = when(Frame).then({ 58 if (parent.finished is false) return; 59 static if (is(P.Ret == void)) { 60 this.exec(f); 61 } else { 62 this.exec(f, parent.result.get()); 63 } 64 }); 65 } 66 67 private void exec(Args...)(T delegate(Args) f, Args args) { 68 execWithErrorHandling({ 69 static if (is(T == void)) { 70 f(args); 71 } else { 72 result = f(args).nullable; 73 } 74 }); 75 } 76 77 private void exec(Args...)(Promise!T delegate(Args) f, Args args) { 78 execWithErrorHandling({ 79 static if (is(T == void)) { 80 f(args).then({ 81 this.task.kill(); 82 }); 83 } else { 84 f(args).then((r) { 85 result = r.nullable; 86 this.task.kill(); 87 }); 88 } 89 }); 90 } 91 92 private void execWithErrorHandling(void delegate() func) { 93 try { 94 func(); 95 } catch (Exception e) { 96 this.e = e; 97 } 98 } 99 100 auto then(F)(F f) { 101 static if (isInstanceOf!(Promise, ReturnType!F)) { 102 static if (is(F == delegate)) { 103 return new Promise!(ReturnType!(F).Type)(f, this); 104 } else { 105 return new Promise!(ReturnType!(F).Type)(f.toDelegate(), this); 106 } 107 } else { 108 static if (is(F == delegate)) { 109 return new Promise!(ReturnType!F)(f, this); 110 } else { 111 return new Promise!(ReturnType!F)(f.toDelegate(), this); 112 } 113 } 114 } 115 116 auto error(Ex)(void delegate(Ex) f) { 117 when(this.e !is null).once({ 118 f(cast(Ex)this.e); 119 }); 120 return this; 121 } 122 123 bool finished() 124 { 125 return this.task.isAlive is false; 126 } 127 } 128 129 auto promise(alias f)(Parameters!f args) { 130 static if (is (f == delegate)) { 131 return new Promise!(ReturnType!f)(f, args); 132 } else { 133 return new Promise!(ReturnType!f)(f.toDelegate(), args); 134 } 135 } 136 137 auto promise(alias f)() if (is(Parameters!f[0] == delegate)) { 138 static if (is (f == delegate)) { 139 return new Promise!(Parameters!(Parameters!f[0])[0])(f); 140 } else { 141 return new Promise!(Parameters!(Parameters!f[0])[0])(f.toDelegate()); 142 } 143 }