1 module dpromise.promise; 2 3 import std.traits; 4 import std.variant : Algebraic, tryVisit, visit; 5 6 private template ResolveFunc(T) { 7 static if(!is(T == void)) { 8 alias ResolveFunc = void delegate(T) nothrow; 9 }else { 10 alias ResolveFunc = void delegate() nothrow; 11 } 12 } 13 private alias RejectFunc(T) = void delegate(Exception) nothrow; 14 public Promise!T promise(T)(void delegate(ResolveFunc!T resolve, RejectFunc!T reject) executer) nothrow 15 if(!is(Unqual!T : Exception) && !is(Unqual!T : Promise!K, K)) 16 in { 17 assert(executer !is null); 18 } body { 19 return new Promise!T((ret) nothrow { 20 21 static if(!is(T == void)) { 22 void resolve(T v) nothrow { 23 Either!T a = v; 24 ret(a); 25 } 26 }else { 27 void resolve() nothrow { 28 ret(Either!T.init); 29 } 30 } 31 void reject(Exception e) nothrow { 32 Either!T a = e; 33 ret(a); 34 } 35 36 try{ 37 executer(&resolve, &reject); 38 }catch(Exception e) { 39 reject(e); 40 } 41 });} 42 43 44 alias Either(T) = Algebraic!(T, Exception); 45 46 public abstract class Awaiter { 47 abstract @property @safe /*@nogc*/ nothrow { 48 bool isPending() const nothrow; 49 bool isFulfilled() const nothrow; 50 bool isRejected() const nothrow; 51 } 52 53 abstract public Awaiter then(void delegate() onFulfillment, void delegate(Exception) onRejection) nothrow; 54 } 55 56 public final class Promise(T) : Awaiter if(!is(Unqual!T : Exception) && !is(Unqual!T : Promise!K, K)) { 57 protected { 58 Either!T _value; 59 static if(is(T == void)) bool _isPending = true; 60 void delegate() nothrow next; 61 } 62 63 @property @trusted /*@nogc*/ { 64 override bool isPending() const nothrow { 65 static if(!is(T == void)) { 66 return !_value.hasValue; 67 }else { 68 return !_value.hasValue && this._isPending; 69 } 70 } 71 72 override bool isFulfilled() const nothrow { 73 return !this.isPending && _value.type !is typeid(Exception); 74 } 75 76 override bool isRejected() const nothrow { 77 return !this.isPending && _value.type is typeid(Exception); 78 } 79 static if(!is(T == void)) 80 inout(Unqual!T) value() inout { 81 if(this.isFulfilled) { 82 return _value.get!(Unqual!T); 83 }else { 84 assert(0); 85 } 86 } 87 88 inout(Exception) exception() inout { 89 if(this.isRejected) { 90 return _value.get!Exception; 91 }else { 92 assert(0); 93 } 94 } 95 } 96 97 private this() @safe nothrow { 98 this.next = (){}; 99 } 100 101 package(dpromise) this(void delegate(void delegate(Either!T) nothrow) nothrow executer) nothrow { 102 void ret(Either!T v) nothrow { 103 if(!this.isPending) return; 104 try { 105 this._value = v; 106 }catch(Exception e){} //例外は発生しない 107 static if(is(T == void)) this._isPending = false; 108 this.next(); 109 } 110 this(); 111 executer(&ret); 112 } 113 114 private template Flatten(S) { 115 static if(is(Unqual!S : Promise!U, U)) { 116 alias Flatten = U; 117 }else { 118 alias Flatten = S; 119 } 120 } 121 122 override Promise!void then(void delegate() onFulfillment, void delegate(Exception) onRejection) nothrow { 123 return thenImpl(onFulfillment, onRejection); 124 } 125 126 static if(!is(T == void)) { 127 public Promise!(Flatten!S) then(S, U)( 128 S delegate(T) onFulfillment, 129 U delegate(Exception) onRejection = cast(S delegate(Exception))null 130 ) nothrow if(is(Flatten!S == Flatten!U)) 131 in { 132 assert(onFulfillment !is null); 133 }body { 134 if(onRejection is null) { 135 onRejection = (e){ throw e; }; 136 } 137 return thenImpl( 138 () { 139 return onFulfillment(this.value); 140 }, 141 onRejection 142 ); 143 } 144 } 145 146 public Promise!(Flatten!S) then(S, U)( 147 S delegate() onFulfillment, 148 U delegate(Exception) onRejection = cast(S delegate(Exception))null 149 ) nothrow if(is(Flatten!S == Flatten!U)) 150 in { 151 assert(onFulfillment !is null); 152 }body { 153 154 if(onRejection is null) { 155 onRejection = (e){ throw e; }; 156 } 157 return thenImpl( 158 onFulfillment, onRejection 159 ); 160 } 161 162 public Promise!T fail(T delegate(Exception) onRejection) nothrow { 163 if(onRejection is null) { 164 onRejection = (e){ throw e; }; 165 } 166 return thenImpl( 167 () @safe { 168 static if(!is(T == void)) return this.value; 169 }, 170 onRejection 171 ); 172 } 173 174 private Promise!(Flatten!S) thenImpl(S, U)( 175 S delegate() onFulfillment, 176 U delegate(Exception) onRejection 177 ) nothrow if(is(Flatten!S == Flatten!U)) 178 in { 179 assert(onFulfillment !is null); 180 assert(onRejection !is null); 181 }body { 182 auto child = new Promise!(Flatten!S)(); 183 this.next = () nothrow { 184 void fulfill() { 185 static if(!is(S : Promise!K, K)) { 186 static if(!is(Flatten!S == void)) { 187 child._value = onFulfillment(); 188 }else { 189 onFulfillment(); 190 child._isPending = false; 191 } 192 child.next(); 193 }else { 194 static if(!is(Flatten!S == void)) { 195 onFulfillment().then( 196 (v) { 197 child._value = v; 198 child.next(); 199 }, 200 (e) { 201 child._value = e; 202 child.next(); 203 } 204 ); 205 }else { 206 onFulfillment().then( 207 () { 208 child._isPending = false; 209 child.next(); 210 }, 211 (e) { 212 child._value = e; 213 child.next(); 214 } 215 ); 216 } 217 } 218 } 219 220 void reject(Exception exception) { 221 static if(!is(U : Promise!K, K)) { 222 static if(!is(Flatten!U == void)) { 223 child._value = onRejection(exception); 224 }else { 225 onRejection(exception); 226 child._isPending = false; 227 } 228 child.next(); 229 }else { 230 static if(!is(Flatten!U == void)) { 231 onRejection(exception).then( 232 (v) { 233 child._value = v; 234 child.next(); 235 }, 236 (e) { 237 child._value = e; 238 child.next(); 239 } 240 ); 241 }else { 242 onRejection(exception).then( 243 () { 244 child._isPending = false; 245 child.next(); 246 }, 247 (e) { 248 child._value = e; 249 child.next(); 250 } 251 ); 252 } 253 } 254 } 255 256 try { 257 this._value.tryVisit!( 258 (Exception e) => reject(e), 259 () => fulfill() 260 ); 261 }catch(Exception e) { 262 try{ 263 child._value = e; 264 }catch(Exception e){} //例外は発生しない 265 child.next(); 266 } 267 }; 268 269 if(!this.isPending) this.next(); 270 271 return child; 272 } 273 }