44
55import 'dart:async' ;
66
7+ import 'cancelable_operation.dart' ;
8+
9+ /// A sentinel object indicating that a member of a [FutureGroup] was canceled
10+ /// rather than completing normally.
11+ const _canceledResult = Object ();
12+
713/// A collection of futures waits until all added [Future] s complete.
814///
915/// Futures are added to the group with [add] . Once you're finished adding
@@ -61,12 +67,21 @@ class FutureGroup<T> implements Sink<Future<T>> {
6167 /// The values emitted by the futures that have been added to the group, in
6268 /// the order they were added.
6369 ///
64- /// The slots for futures that haven't completed yet are `null` .
65- final _values = < T ? > [];
70+ /// This is type `Object?` rather than `T?` so it can contain
71+ /// [_canceledResult] . The slots for futures that haven't completed yet are
72+ /// `null` .
73+ final _values = < Object ? > [];
6674
6775 /// Wait for [task] to complete.
6876 @override
69- void add (Future <T > task) {
77+ void add (Future <T > task) =>
78+ addCancelable (CancelableOperation .fromFuture (task));
79+
80+ /// Wait for [task] to complete.
81+ ///
82+ /// If [task] is canceled, it's removed from the group without adding a value
83+ /// to [future] .
84+ void addCancelable (CancelableOperation <T > task) {
7085 if (_closed) throw StateError ('The FutureGroup is closed.' );
7186
7287 // Ensure that future values are put into [values] in the same order they're
@@ -76,19 +91,22 @@ class FutureGroup<T> implements Sink<Future<T>> {
7691 _values.add (null );
7792
7893 _pending++ ;
79- task.then ((value) {
94+ task.valueOrCancellation (). then ((value) {
8095 if (_completer.isCompleted) return null ;
8196
8297 _pending-- ;
83- _values[index] = value;
98+ _values[index] = task.isCanceled ? _canceledResult : value;
8499
85100 if (_pending != 0 ) return null ;
86101 var onIdleController = _onIdleController;
87102 if (onIdleController != null ) onIdleController.add (null );
88103
89104 if (! _closed) return null ;
90105 if (onIdleController != null ) onIdleController.close ();
91- _completer.complete (_values.whereType <T >().toList ());
106+ _completer.complete ([
107+ for (var value in _values)
108+ if (value != _canceledResult && value is T ) value
109+ ]);
92110 }).catchError ((Object error, StackTrace stackTrace) {
93111 if (_completer.isCompleted) return null ;
94112 _completer.completeError (error, stackTrace);
0 commit comments