1 /** 2 * async/await-like API for asynchronous tasks combining promises and 3 * fibers. 4 * 5 * License: 6 * This Source Code Form is subject to the terms of 7 * the Mozilla Public License, v. 2.0. If a copy of 8 * the MPL was not distributed with this file, You 9 * can obtain one at http://mozilla.org/MPL/2.0/. 10 * 11 * Authors: 12 * Vladimir Panteleev <ae@cy.md> 13 */ 14 15 module ae.utils.promise.await; 16 17 import core.thread : Fiber; 18 19 import ae.utils.promise; 20 21 /// Evaluates `task` in a new fiber, and returns a promise which is 22 /// fulfilled when `task` exits. `task` may use `await` to block on 23 /// other promises. 24 Promise!(T, E) async(T, E = Exception)(lazy T task) 25 { 26 auto p = new Promise!T; 27 auto f = new Fiber({ 28 try 29 static if (is(T == void)) 30 task, p.fulfill(); 31 else 32 p.fulfill(task); 33 catch (E e) 34 p.reject(e); 35 }, 64 * 1024); 36 f.call(); 37 return p; 38 } 39 40 /// Synchronously waits until the promise `p` is fulfilled. 41 /// Can only be called in a fiber. 42 T await(T, E)(Promise!(T, E) p) 43 { 44 Promise!T.ValueTuple fiberValue; 45 E fiberError; 46 47 auto f = Fiber.getThis(); 48 p.then((Promise!T.ValueTuple value) { 49 fiberValue = value; 50 f.call(); 51 }, (E error) { 52 fiberError = error; 53 f.call(); 54 }); 55 Fiber.yield(); 56 if (fiberError) 57 throw fiberError; 58 else 59 { 60 static if (!is(T == void)) 61 return fiberValue[0]; 62 } 63 } 64 65 /// 66 unittest 67 { 68 import ae.net.asockets : socketManager; 69 70 auto one = resolve(1); 71 auto two = resolve(2); 72 73 int sum; 74 async(one.await + two.await).then((value) { 75 sum = value; 76 }); 77 socketManager.loop(); 78 assert(sum == 3); 79 } 80 81 unittest 82 { 83 if (false) 84 { 85 async({}()).await(); 86 } 87 }