Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(589)

Side by Side Diff: lib/src/util/cancelable_future.dart

Issue 1262623006: Temporarily bring in code from the async package. (Closed) Base URL: git@github.com:dart-lang/test@master
Patch Set: Created 5 years, 4 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « no previous file | lib/src/util/forkable_stream.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file.
4
5 // TODO(nweiz): Use this from the async package when
6 // https://codereview.chromium.org/1266603005/ lands.
7 library test.util.cancelable_future;
8
9 import 'dart:async';
10
11 import 'package:async/async.dart';
12
13 /// A [Future] that can be cancelled.
14 ///
15 /// When this is cancelled, that means it won't complete either successfully or
16 /// with an error.
17 ///
18 /// In general it's a good idea to only have a single non-branching chain of
19 /// cancellable futures. If there are multiple branches, any of them that aren't
20 /// closed explicitly will throw a [CancelException] once one of them is
21 /// cancelled.
22 class CancelableFuture<T> implements Future<T> {
23 /// The completer that produced this future.
24 ///
25 /// This is canceled when [cancel] is called.
26 final CancelableCompleter<T> _completer;
27
28 /// The future wrapped by [this].
29 Future<T> _inner;
30
31 /// Whether this future has been canceled.
32 ///
33 /// This is tracked individually for each future because a canceled future
34 /// shouldn't emit events, but the completer will throw a [CancelException].
35 bool _canceled = false;
36
37 CancelableFuture._(this._completer, Future<T> inner) {
38 // Once this future is canceled, it should never complete.
39 _inner = inner.whenComplete(() {
40 if (_canceled) return new Completer().future;
41 });
42 }
43
44 /// Creates a [CancelableFuture] wrapping [inner].
45 ///
46 /// When this future is canceled, [onCancel] will be called. The callback may
47 /// return a Future to indicate that asynchronous work has to be done to
48 /// cancel the future; this Future will be returned by [cancel].
49 factory CancelableFuture.fromFuture(Future<T> inner, [onCancel()]) {
50 var completer = new CancelableCompleter<T>(onCancel);
51 completer.complete(inner);
52 return completer.future;
53 }
54
55 /// Creates a [Stream] containing the result of this future.
56 ///
57 /// If this Future is canceled, the Stream will not produce any events. If a
58 /// subscription to the stream is canceled, this is as well.
59 Stream<T> asStream() {
60 var controller = new StreamController<T>(
61 sync: true, onCancel: _completer._cancel);
62
63 _inner.then((value) {
64 controller.add(value);
65 controller.close();
66 }, onError: (error, stackTrace) {
67 controller.addError(error, stackTrace);
68 controller.close();
69 });
70 return controller.stream;
71 }
72
73 /// Returns [this] as a normal future.
74 ///
75 /// The returned future is different from this one in the following ways:
76 ///
77 /// * Its methods don't return [CancelableFuture]s.
78 ///
79 /// * It doesn't support [cancel] or [asFuture].
80 ///
81 /// * The [Stream] returned by [asStream] won't cancel the future if it's
82 /// canceled.
83 ///
84 /// * If a [timeout] times out, it won't cancel the future.
85 Future asFuture() => _inner;
86
87 CancelableFuture catchError(Function onError, {bool test(error)}) =>
kevmoo 2015/07/29 23:03:46 docs for these?
nweiz 2015/07/29 23:18:10 Generally you shouldn't document inherited members
88 new CancelableFuture._(
89 _completer, _inner.catchError(onError, test: test));
90
91 CancelableFuture then(onValue(T value), {Function onError}) =>
92 new CancelableFuture._(
93 _completer, _inner.then(onValue, onError: onError));
94
95 CancelableFuture<T> whenComplete(action()) =>
96 new CancelableFuture<T>._(_completer, _inner.whenComplete(action));
97
98 /// Time-out the future computation after [timeLimit] has passed.
99 ///
100 /// When the future times out, it will be canceled. Note that the return value
101 /// of the completer's `onCancel` callback will be ignored by default, and any
102 /// errors it produces silently dropped. To avoid this, call [cancel]
103 /// explicitly in [onTimeout].
104 CancelableFuture timeout(Duration timeLimit, {onTimeout()}) {
105 var wrappedOnTimeout = () {
106 // Ignore errors here because there's no good way to pipe them to the
107 // caller without screwing up [onTimeout].
108 _completer._cancel().catchError((_) {});
109 if (onTimeout != null) return onTimeout();
110 throw new TimeoutException("Future not completed", timeLimit);
111 };
112
113 return new CancelableFuture._(
114 _completer, _inner.timeout(timeLimit, onTimeout: wrappedOnTimeout));
115 }
116
117 /// Cancels this future.
118 ///
119 /// This returns the [Future] returned by the [CancelableCompleter]'s
120 /// `onCancel` callback. Unlike [Stream.cancel], it never returns `null`.
121 Future cancel() {
122 _canceled = true;
123 return _completer._cancel();
124 }
125 }
126
127 /// A completer for a [CancelableFuture].
128 class CancelableCompleter<T> implements Completer<T> {
129 /// The completer for the wrapped future.
130 final Completer<T> _inner;
131
132 /// The callback to call if the future is canceled.
133 final ZoneCallback _onCancel;
134
135 CancelableFuture<T> get future => _future;
136 CancelableFuture<T> _future;
137
138 bool get isCompleted => _isCompleted;
139 bool _isCompleted = false;
140
141 /// Whether the completer was canceled before being completed.
142 bool get isCanceled => _isCanceled;
143 bool _isCanceled = false;
144
145 /// Whether the completer has fired.
146 ///
147 /// This is distinct from [isCompleted] when a [Future] is passed to
148 /// [complete]; this won't be `true` until that [Future] fires.
149 bool _fired = false;
150
151 /// Creates a new completer for a [CancelableFuture].
152 ///
153 /// When the future is canceled, as long as the completer hasn't yet
154 /// completed, [onCancel] is called. The callback may return a [Future]; if
155 /// so, that [Future] is returned by [CancelableFuture.cancel].
156 CancelableCompleter([this._onCancel])
157 : _inner = new Completer<T>() {
158 _future = new CancelableFuture<T>._(this, _inner.future);
159 }
160
161 void complete([value]) {
162 if (_isCompleted) throw new StateError("Future already completed");
163 _isCompleted = true;
164
165 if (_isCanceled) return;
166 if (value is! Future) {
167 _fired = true;
168 _inner.complete(value);
169 return;
170 }
171
172 value.then((result) {
173 if (_isCanceled) return;
174 _fired = true;
175 _inner.complete(result);
176 }, onError: (error, stackTrace) {
177 if (_isCanceled) return;
178 _fired = true;
179 _inner.completeError(error, stackTrace);
180 });
181 }
182
183 void completeError(Object error, [StackTrace stackTrace]) {
184 if (_isCompleted) throw new StateError("Future already completed");
185 _isCompleted = true;
186
187 if (_isCanceled) return;
188 _fired = true;
189 _inner.completeError(error, stackTrace);
190 }
191
192 /// Cancel the completer.
193 Future _cancel() => _cancelMemo.runOnce(() {
194 if (_fired) return null;
195 _isCanceled = true;
196
197 // Throw an catch to get access to the current stack trace.
198 try {
199 throw new CancelException();
200 } catch (error, stackTrace) {
201 _inner.completeError(error, stackTrace);
202 }
203
204 if (_onCancel != null) return _onCancel();
205 });
206 final _cancelMemo = new AsyncMemoizer();
207 }
208
209 /// An exception thrown when a [CancelableFuture] is canceled.
210 ///
211 /// Since a canceled [CancelableFuture] doesn't receive any more events, this
212 /// will only be passed to other branches of the future chain.
213 class CancelException implements Exception {
214 CancelException();
215
216 String toString() => "This Future has been canceled.";
217 }
OLDNEW
« no previous file with comments | « no previous file | lib/src/util/forkable_stream.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698