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

Side by Side Diff: lib/src/cancelable_operation.dart

Issue 1266603005: Add a CancelableFuture class. (Closed) Base URL: git@github.com:dart-lang/async.git@master
Patch Set: Convert to CancelableOperation 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 | « lib/async.dart ('k') | test/cancelable_operation_test.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 library async.cancelable_operation;
6
7 import 'dart:async';
8
9 import 'package:async/async.dart';
10
11 /// An asynchronuos operation that can be cancelled.
Lasse Reichstein Nielsen 2015/08/27 10:20:54 So basically, you have the result of an async oper
nweiz 2015/08/28 00:34:56 All this is true, although CancelableCompleter is
12 ///
13 /// The value of this operation is exposed as [value]. When this operation is
14 /// cancelled, [value] won't complete either successfully or with an error. If
15 /// [value] has already completed, cancelling the operation does nothing.
16 class CancelableOperation<T> {
17 /// The completer that produced this operation.
18 ///
19 /// This is canceled when [cancel] is called.
20 final CancelableCompleter<T> _completer;
21
22 Future<T> get value => _completer._inner.future;
Lasse Reichstein Nielsen 2015/08/27 10:20:53 I'd call this "result" since it may be an error. W
Lasse Reichstein Nielsen 2015/08/27 10:20:54 Move getter below constructor.
nweiz 2015/08/28 00:34:56 "result" seems confusing when the package has a "R
nweiz 2015/08/28 00:34:56 Done, although this is contrary to the style most
Lasse Reichstein Nielsen 2015/09/03 13:06:17 The order in the file is independent of how the AP
23
24 /// Whether this operation has been canceled.
25 bool _canceled = false;
26
27 CancelableOperation._(this._completer);
Lasse Reichstein Nielsen 2015/08/27 10:57:41 I think one thing that makes it hard for me to wra
Lasse Reichstein Nielsen 2015/08/27 10:59:47 And it is, the other one was the cancelable comple
nweiz 2015/08/28 00:34:55 That's true, but I expect exposing operations crea
28
29 /// Creates a [CancelableOperation] wrapping [inner].
30 ///
31 /// When this operation is canceled, [onCancel] will be called and any value
32 /// or error produced by [inner] will be discarded. The callback may return a
33 /// Future to indicate that asynchronous work has to be done to cancel the
34 /// future; this Future will be returned by [cancel].
35 factory CancelableOperation.fromFuture(Future<T> inner, {onCancel()}) {
Lasse Reichstein Nielsen 2015/08/27 10:20:54 Why is onCancel optional? If it's null, I don't se
nweiz 2015/08/28 00:34:56 From the user's perspective, canceling an operatio
Lasse Reichstein Nielsen 2015/09/03 13:06:17 Ack, makes sense. Cancel only cancels the "operati
36 var completer = new CancelableCompleter<T>(onCancel: onCancel);
37 completer.complete(inner);
38 return completer.operation;
Lasse Reichstein Nielsen 2015/08/27 10:20:54 You are passing a callback here, which is not goin
nweiz 2015/08/28 00:34:56 I don't think it's very likely that multiple dispa
Lasse Reichstein Nielsen 2015/09/03 13:06:17 True. It has to be documented when the callback wi
nweiz 2015/09/08 21:14:45 Done.
39 }
40
41 /// Creates a [Stream] containing the result of this operation.
42 ///
43 /// This is like `value.asStream()`, but if a subscription to the stream is
44 /// canceled, this is as well.
45 Stream<T> asStream() {
Lasse Reichstein Nielsen 2015/08/27 10:20:54 I prefer to make this a getter.
nweiz 2015/08/28 00:34:56 I think it's more important for it to be consisten
Lasse Reichstein Nielsen 2015/09/03 13:06:17 Ok, that's fair.
46 var controller = new StreamController<T>(
47 sync: true, onCancel: _completer._cancel);
48
49 value.then((value) {
50 controller.add(value);
51 controller.close();
52 }, onError: (error, stackTrace) {
53 controller.addError(error, stackTrace);
54 controller.close();
55 });
56 return controller.stream;
57 }
58
59 /// Cancels this operation.
60 ///
61 /// This returns the [Future] returned by the [CancelableCompleter]'s
62 /// `onCancel` callback. Unlike [Stream.cancel], it never returns `null`.
63 Future cancel() {
64 _canceled = true;
Lasse Reichstein Nielsen 2015/09/03 13:06:17 Maybe drop the _canceled field in this class and j
nweiz 2015/09/08 21:14:45 We don't actually use this field anyway, it turns
65 return _completer._cancel();
66 }
67 }
68
69 /// A completer for a [CancelableOperation].
70 class CancelableCompleter<T> {
Lasse Reichstein Nielsen 2015/08/27 10:20:54 I don't think you need this class. Do you *want* i
nweiz 2015/08/28 00:34:56 Yeah; see above comments.
71 /// The completer for the wrapped future.
72 final Completer<T> _inner;
73
74 /// The callback to call if the future is canceled.
75 final ZoneCallback _onCancel;
76
77 CancelableOperation<T> get operation => _operation;
78 CancelableOperation<T> _operation;
Lasse Reichstein Nielsen 2015/08/27 10:20:53 I find it very hard to see which fields the class
nweiz 2015/08/28 00:34:56 Done, although see above.
79
80 /// Whether the completer has completed.
81 bool get isCompleted => _isCompleted;
82 bool _isCompleted = false;
83
84 /// Whether the completer was canceled before being completed.
85 bool get isCanceled => _isCanceled;
86 bool _isCanceled = false;
87
88 /// Whether the completer has fired.
89 ///
90 /// This is distinct from [isCompleted] when a [Future] is passed to
91 /// [complete]; this won't be `true` until that [Future] fires.
92 bool _fired = false;
Lasse Reichstein Nielsen 2015/09/03 13:06:17 I think _fired is equivalent to _inner.isCompleted
nweiz 2015/09/08 21:14:45 Done.
93
94 /// Creates a new completer for a [CancelableOperation].
95 ///
96 /// When the future operation canceled, as long as the completer hasn't yet
97 /// completed, [onCancel] is called. The callback may return a [Future]; if
98 /// so, that [Future] is returned by [CancelableOperation.cancel].
99 CancelableCompleter({onCancel()})
100 : _onCancel = onCancel,
101 _inner = new Completer<T>() {
102 _operation = new CancelableOperation<T>._(this);
103 }
104
105 /// Completes [operation] to [value].
106 ///
107 /// If [value] is a [Future], this will complete to the result of that
108 /// [Future] once it completes.
109 void complete([value]) {
110 if (_isCompleted) throw new StateError("Operation already completed");
111 _isCompleted = true;
112
113 if (_isCanceled) return;
Lasse Reichstein Nielsen 2015/08/27 10:20:54 If value is a future with an error, the error is n
nweiz 2015/08/28 00:34:56 Done.
114 if (value is! Future) {
115 _fired = true;
116 _inner.complete(value);
117 return;
118 }
119
120 value.then((result) {
121 if (_isCanceled) return;
122 _fired = true;
123 _inner.complete(result);
124 }, onError: (error, stackTrace) {
125 if (_isCanceled) return;
126 _fired = true;
127 _inner.completeError(error, stackTrace);
128 });
129 }
130
131 /// Completes [operation] to [error].
132 void completeError(Object error, [StackTrace stackTrace]) {
133 if (_isCompleted) throw new StateError("Operation already completed");
134 _isCompleted = true;
135
136 if (_isCanceled) return;
137 _fired = true;
138 _inner.completeError(error, stackTrace);
139 }
140
141 /// Cancel the completer.
142 Future _cancel() => _cancelMemo.runOnce(() {
143 if (_fired) return null;
144 _isCanceled = true;
145 if (_onCancel != null) return _onCancel();
146 });
147 final _cancelMemo = new AsyncMemoizer();
Lasse Reichstein Nielsen 2015/08/27 10:20:54 Move field to top of class.
nweiz 2015/08/28 00:34:56 I will if you insist, but I think it's a lot clear
Lasse Reichstein Nielsen 2015/09/03 13:06:17 I still prefer to have all the fields collected in
nweiz 2015/09/08 21:14:45 Done.
148 }
OLDNEW
« no previous file with comments | « lib/async.dart ('k') | test/cancelable_operation_test.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698