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.sys.timing; 20 import ae.utils.promise; 21 22 /// Given a range of promises, resolve them one after another, 23 /// and return a promise which is fulfilled when all promises in `range` are fulfilled. 24 /// `range` may be a lazy range (e.g. a `map` which produces promises from other input), 25 /// which will cause the work to be started only when the previous promise completes. 26 PromiseValueTransform!(ElementType!R, x => [x]) allSerial(R)(R range) 27 if (isInputRange!R) 28 { 29 auto p = new typeof(return); 30 31 alias P = ElementType!R; 32 alias T = PromiseValue!P; 33 alias E = PromiseError!P; 34 35 typeof(p).ValueTuple results; 36 static if (!is(T == void)) 37 { 38 static if (hasLength!R) 39 results[0].reserve(range.length); 40 } 41 42 void next() 43 { 44 if (range.empty) 45 p.fulfill(results); 46 else 47 { 48 range.front.then((P.ValueTuple value) { 49 static if (!is(T == void)) 50 results[0] ~= value[0]; 51 next(); 52 }, (E error) { 53 p.reject(error); 54 }); 55 range.popFront(); 56 } 57 } 58 59 next(); 60 61 return p; 62 } 63 64 unittest 65 { 66 import std.algorithm.iteration : map; 67 size_t sum; 68 [1, 2, 3] 69 .map!((n) { 70 auto nextSum = sum + n; 71 auto p = new Promise!void(); 72 setTimeout({ sum = nextSum; p.fulfill(); }, 0.seconds); 73 return p; 74 }) 75 .allSerial; 76 socketManager.loop(); 77 assert(sum == 6); 78 }