@@ -281,10 +281,10 @@ function coroutine(callable $function, ...$args): PromiseInterface
281281}
282282
283283/**
284- * @param array <callable():PromiseInterface<mixed,Exception>> $tasks
284+ * @param iterable <callable():PromiseInterface<mixed,Exception>> $tasks
285285 * @return PromiseInterface<array<mixed>,Exception>
286286 */
287- function parallel (array $ tasks ): PromiseInterface
287+ function parallel (iterable $ tasks ): PromiseInterface
288288{
289289 $ pending = [];
290290 $ deferred = new Deferred (function () use (&$ pending ) {
@@ -296,15 +296,10 @@ function parallel(array $tasks): PromiseInterface
296296 $ pending = [];
297297 });
298298 $ results = [];
299- $ errored = false ;
299+ $ continue = true ;
300300
301- $ numTasks = count ($ tasks );
302- if (0 === $ numTasks ) {
303- $ deferred ->resolve ($ results );
304- }
305-
306- $ taskErrback = function ($ error ) use (&$ pending , $ deferred , &$ errored ) {
307- $ errored = true ;
301+ $ taskErrback = function ($ error ) use (&$ pending , $ deferred , &$ continue ) {
302+ $ continue = false ;
308303 $ deferred ->reject ($ error );
309304
310305 foreach ($ pending as $ promise ) {
@@ -316,33 +311,39 @@ function parallel(array $tasks): PromiseInterface
316311 };
317312
318313 foreach ($ tasks as $ i => $ task ) {
319- $ taskCallback = function ($ result ) use (&$ results , &$ pending , $ numTasks , $ i , $ deferred ) {
314+ $ taskCallback = function ($ result ) use (&$ results , &$ pending , & $ continue , $ i , $ deferred ) {
320315 $ results [$ i ] = $ result ;
316+ unset($ pending [$ i ]);
321317
322- if (count ( $ results ) === $ numTasks ) {
318+ if (! $ pending && ! $ continue ) {
323319 $ deferred ->resolve ($ results );
324320 }
325321 };
326322
327- $ promise = call_user_func ($ task );
323+ $ promise = \ call_user_func ($ task );
328324 assert ($ promise instanceof PromiseInterface);
329325 $ pending [$ i ] = $ promise ;
330326
331327 $ promise ->then ($ taskCallback , $ taskErrback );
332328
333- if ($ errored ) {
329+ if (! $ continue ) {
334330 break ;
335331 }
336332 }
337333
334+ $ continue = false ;
335+ if (!$ pending ) {
336+ $ deferred ->resolve ($ results );
337+ }
338+
338339 return $ deferred ->promise ();
339340}
340341
341342/**
342- * @param array <callable():PromiseInterface<mixed,Exception>> $tasks
343+ * @param iterable <callable():PromiseInterface<mixed,Exception>> $tasks
343344 * @return PromiseInterface<array<mixed>,Exception>
344345 */
345- function series (array $ tasks ): PromiseInterface
346+ function series (iterable $ tasks ): PromiseInterface
346347{
347348 $ pending = null ;
348349 $ deferred = new Deferred (function () use (&$ pending ) {
@@ -353,20 +354,31 @@ function series(array $tasks): PromiseInterface
353354 });
354355 $ results = [];
355356
357+ if ($ tasks instanceof \IteratorAggregate) {
358+ $ tasks = $ tasks ->getIterator ();
359+ assert ($ tasks instanceof \Iterator);
360+ }
361+
356362 /** @var callable():void $next */
357363 $ taskCallback = function ($ result ) use (&$ results , &$ next ) {
358364 $ results [] = $ result ;
359365 $ next ();
360366 };
361367
362368 $ next = function () use (&$ tasks , $ taskCallback , $ deferred , &$ results , &$ pending ) {
363- if (0 === count ( $ tasks) ) {
369+ if ($ tasks instanceof \Iterator ? ! $ tasks-> valid () : ! $ tasks ) {
364370 $ deferred ->resolve ($ results );
365371 return ;
366372 }
367373
368- $ task = array_shift ($ tasks );
369- $ promise = call_user_func ($ task );
374+ if ($ tasks instanceof \Iterator) {
375+ $ task = $ tasks ->current ();
376+ $ tasks ->next ();
377+ } else {
378+ $ task = \array_shift ($ tasks );
379+ }
380+
381+ $ promise = \call_user_func ($ task );
370382 assert ($ promise instanceof PromiseInterface);
371383 $ pending = $ promise ;
372384
@@ -379,10 +391,10 @@ function series(array $tasks): PromiseInterface
379391}
380392
381393/**
382- * @param array <callable(mixed=):PromiseInterface<mixed,Exception>> $tasks
394+ * @param iterable <callable(mixed=):PromiseInterface<mixed,Exception>> $tasks
383395 * @return PromiseInterface<mixed,Exception>
384396 */
385- function waterfall (array $ tasks ): PromiseInterface
397+ function waterfall (iterable $ tasks ): PromiseInterface
386398{
387399 $ pending = null ;
388400 $ deferred = new Deferred (function () use (&$ pending ) {
@@ -392,15 +404,26 @@ function waterfall(array $tasks): PromiseInterface
392404 $ pending = null ;
393405 });
394406
407+ if ($ tasks instanceof \IteratorAggregate) {
408+ $ tasks = $ tasks ->getIterator ();
409+ assert ($ tasks instanceof \Iterator);
410+ }
411+
395412 /** @var callable $next */
396413 $ next = function ($ value = null ) use (&$ tasks , &$ next , $ deferred , &$ pending ) {
397- if (0 === count ( $ tasks) ) {
414+ if ($ tasks instanceof \Iterator ? ! $ tasks-> valid () : ! $ tasks ) {
398415 $ deferred ->resolve ($ value );
399416 return ;
400417 }
401418
402- $ task = array_shift ($ tasks );
403- $ promise = call_user_func_array ($ task , func_get_args ());
419+ if ($ tasks instanceof \Iterator) {
420+ $ task = $ tasks ->current ();
421+ $ tasks ->next ();
422+ } else {
423+ $ task = \array_shift ($ tasks );
424+ }
425+
426+ $ promise = \call_user_func_array ($ task , func_get_args ());
404427 assert ($ promise instanceof PromiseInterface);
405428 $ pending = $ promise ;
406429
0 commit comments