combineAsync<T extends Object> function

Async<List<T>> combineAsync<T extends Object>(
  1. Iterable<Async<T>> asyncs, {
  2. @noFutures Err<List<T>> onErr(
    1. List<Result<T>> allResults
    )?,
})

Combines an iterable of Asyncs into one containing a list of their values.

The inputs are awaited concurrently. If any resolves to an Err, applies the onErr function to combine errors.

The input iterable is consumed exactly once, so it is safe to pass a single-pass iterable.

Implementation

Async<List<T>> combineAsync<T extends Object>(
  Iterable<Async<T>> asyncs, {
  @noFutures Err<List<T>> Function(List<Result<T>> allResults)? onErr,
}) {
  // Materialize once: `isEmpty` and the subsequent `.map(...)` passed to
  // `Future.wait` would otherwise iterate the input twice.
  final list = asyncs.toList(growable: false);
  if (list.isEmpty) {
    return Async.okValue([]);
  }

  return Async(() async {
    final results = await Future.wait(list.map((a) => a.value));
    final combined = combineResult(results, onErr: onErr);
    switch (combined) {
      case Ok(value: final value):
        return value;
      case Err err:
        throw err;
    }
  });
}