combineResolvable<T extends Object> function

Resolvable<List<T>> combineResolvable<T extends Object>(
  1. Iterable<Resolvable<T>> resolvables, {
  2. @noFutures Err<List<T>> onErr(
    1. List<Result<T>> allResults
    )?,
})

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

The result is an Async if any of the resolvables are Async If any resolvable contains an Err, applies onErr to combine errors.

The input iterable is consumed exactly once, so it is safe to pass a single-pass iterable (e.g. a sync* generator).

Implementation

Resolvable<List<T>> combineResolvable<T extends Object>(
  Iterable<Resolvable<T>> resolvables, {
  @noFutures Err<List<T>> Function(List<Result<T>> allResults)? onErr,
}) {
  // Materialize once. Single-pass iterables (sync* generators) would
  // otherwise be exhausted by the `.any()` probe below and the subsequent
  // `.map()` would silently see zero elements.
  final list = resolvables.toList(growable: false);
  if (list.isEmpty) {
    return Sync.okValue([]);
  }

  // If any resolvable is async, the result must be async.
  var hasAsync = false;
  for (final r in list) {
    if (r.isAsync()) {
      hasAsync = true;
      break;
    }
  }
  if (hasAsync) {
    return combineAsync(list.map((r) => r.toAsync()), onErr: onErr);
  }
  return combineSync(list.map((r) => r as Sync<T>), onErr: onErr);
}