1 /** 2 * Promise range tools. 3 * 4 * License: 5 * This Source Code Form is subject to the terms of 6 * the Mozilla Public License, v. 2.0. If a copy of 7 * the MPL was not distributed with this file, You 8 * can obtain one at http://mozilla.org/MPL/2.0/. 9 * 10 * Authors: 11 * Vladimir Panteleev <ae@cy.md> 12 */ 13 14 module ae.utils.promise.range; 15 16 import std.range.primitives; 17 18 import ae.net.asockets : socketManager; 19 import ae.utils.promise; 20 21 /// Given a range of promises, resolve them one after another, 22 /// and return a promise which is fulfilled when all promises in `range` are fulfilled. 23 /// `range` may be a lazy range (e.g. a `map` which produces promises from other input), 24 /// which will cause the work to be started only when the previous promise completes. 25 PromiseValueTransform!(ElementType!R, x => [x]) allSerial(R)(R range) 26 if (isInputRange!R) 27 { 28 auto p = new typeof(return); 29 30 alias P = ElementType!R; 31 alias T = PromiseValue!P; 32 alias E = PromiseError!P; 33 34 typeof(p).ValueTuple results; 35 static if (!is(T == void)) 36 { 37 static if (hasLength!R) 38 results[0].reserve(range.length); 39 } 40 41 void next() 42 { 43 if (range.empty) 44 p.fulfill(results); 45 else 46 { 47 range.front.then((P.ValueTuple value) { 48 static if (!is(T == void)) 49 results[0] ~= value[0]; 50 next(); 51 }, (E error) { 52 p.reject(error); 53 }); 54 range.popFront(); 55 } 56 } 57 58 next(); 59 60 return p; 61 } 62 63 unittest 64 { 65 import std.algorithm.iteration : map; 66 import ae.sys.timing : setTimeout; 67 import core.time : seconds; 68 69 size_t sum; 70 [1, 2, 3] 71 .map!((n) { 72 auto nextSum = sum + n; 73 auto p = new Promise!void(); 74 setTimeout({ sum = nextSum; p.fulfill(); }, 0.seconds); 75 return p; 76 }) 77 .allSerial; 78 socketManager.loop(); 79 assert(sum == 6); 80 }