// Copyright (c) 2021, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

import 'dart:async';

import 'package:async/async.dart';

/// Returns a single-subscription stream that emits the results of [operations]
/// in the order they complete.
///
/// If the subscription is canceled, any pending operations are canceled as
/// well.
Stream<T> inCompletionOrder<T>(Iterable<CancelableOperation<T>> operations) {
  var operationSet = operations.toSet();
  var controller = StreamController<T>(
    sync: true,
    onCancel:
        () => Future.wait(operationSet.map((operation) => operation.cancel())),
  );

  for (var operation in operationSet) {
    operation.value
        .then((value) => controller.add(value))
        .onError(controller.addError)
        .whenComplete(() {
          operationSet.remove(operation);
          if (operationSet.isEmpty) controller.close();
        });
  }

  return controller.stream;
}
