1 module upromised.operations; 2 import std.array : empty, front, popFront; 3 import std.range : isInputRange; 4 import upromised.promise : Promise, PromiseIterator; 5 6 PromiseIterator!(typeof(T.init.front)) toAsync(T)(T input) nothrow 7 if (isInputRange!T) 8 { 9 return new class PromiseIterator!(typeof(T.init.front)) { 10 override Promise!ItValue next(Promise!bool) { 11 if (input.empty) { 12 return Promise!ItValue.resolved(ItValue(true)); 13 } else { 14 auto value = ItValue(false, input.front); 15 input.popFront; 16 return Promise!ItValue.resolved(value); 17 } 18 } 19 }; 20 } 21 unittest { 22 auto b = [1, 2, 3].toAsync; 23 int calls = 0; 24 25 b.each((num) { 26 assert(num == 1); 27 assert(calls++ == 0); 28 return false; 29 }).then((eof) { 30 assert(!eof); 31 assert(calls++ == 1); 32 }).nothrow_().then(() { 33 return b.each((num) { 34 assert(num == calls++); 35 }); 36 }).then((eof) { 37 assert(eof); 38 assert(calls++ == 4); 39 }).nothrow_(); 40 41 assert(calls == 5); 42 } 43 unittest { 44 auto b = (new class Object { 45 int front; 46 void popFront() { 47 front++; 48 } 49 bool empty() { 50 return false; 51 } 52 }).toAsync; 53 54 int calls; 55 b.each((num) { 56 assert(calls++ == num); 57 return num < 3; 58 }).then((eof) { 59 assert(!eof); 60 assert(calls++ == 4); 61 }).nothrow_(); 62 63 assert(calls == 5); 64 } 65 PromiseIterator!(T[]) toAsyncChunks(T)(T[] input, size_t chunkLength = 1024) nothrow { 66 import std.algorithm : min; 67 68 return new class PromiseIterator!(T[]) { 69 override Promise!ItValue next(Promise!bool) { 70 if (input.length == 0) { 71 return Promise!ItValue.resolved(ItValue(true)); 72 } else { 73 auto length = input.length.min(chunkLength); 74 const auto value = input[0..length]; 75 input = input[length..$]; 76 return Promise!ItValue.resolved(ItValue(false, value)); 77 } 78 } 79 }; 80 } 81 unittest { 82 import std.array : join; 83 84 auto expected = ["abc", "def", "gh"]; 85 int calls = 0; 86 87 expected.join.toAsyncChunks(3).each((chunk) { 88 assert(chunk == expected[calls]); 89 calls++; 90 }).then((eof) { 91 assert(eof); 92 assert(calls++ == 3); 93 }).nothrow_(); 94 95 assert(calls == 4); 96 } 97 98 Promise!(T[]) readAll(T)(PromiseIterator!T input) nothrow { 99 T[] r; 100 return input.each((value) { 101 r ~= value; 102 }).then((_) => r); 103 } 104 unittest { 105 int[] all; 106 [1, 2, 3].toAsync.readAll.then((allArg) { 107 all = allArg; 108 }).nothrow_(); 109 110 assert(all == [1, 2, 3]); 111 } 112 113 Promise!(T[]) readAllChunks(T)(PromiseIterator!(T[]) input) nothrow { 114 T[] r; 115 return input.each((value) { 116 r ~= value; 117 }).then((_) => r); 118 } 119 unittest { 120 const(char)[] all; 121 ["Hello ", "World"].toAsync.readAllChunks.then((allArg) { 122 all = allArg; 123 }).nothrow_(); 124 125 assert(all == "Hello World"); 126 }