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

Side by Side Diff: pkg/async/lib/result.dart

Issue 255123002: Add capture/release for results in package:async (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: More tests. Created 6 years, 7 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 | Annotate | Revision Log
« no previous file with comments | « pkg/async/lib/async.dart ('k') | pkg/async/pubspec.yaml » ('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) 2013, 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 /**
6 * Capture asynchronous results into synchronous values, and release them again.
7 *
8 * Capturing a result (either a returned value or a thrown error)
9 * means converting it into a [Result] -
10 * either a [ValueResult] or an [ErrorResult].
11 *
12 * This value can release itself by writing itself either to a
13 * [EventSink] or a [Completer], or by becoming a [Future].
14 */
15 library dart.pkg.async.results;
16
17 import "dart:async";
18
19 /**
20 * The result of a computation.
21 */
22 abstract class Result<T> {
23 /**
24 * Create a `Result` with the result of calling [computation].
25 *
26 * This generates either a [ValueResult] with the value returned by
27 * calling `computation`, or an [ErrorResult] with an error thrown by
28 * the call.
29 */
30 Result(T computation()) {
31 try {
32 return new ValueResult(computation());
33 } catch (e, s) {
34 return new ErrorResult(e, s);
35 }
36 }
37
38 /**
39 * Create a `Result` holding a value.
40 *
41 * Alias for [ValueResult.ValueResult].
42 */
43 factory Result.value(T value) = ValueResult<T>;
44
45 /**
46 * Create a `Result` holding an error.
47 *
48 * Alias for [ErrorResult.ErrorResult].
49 */
50 factory Result.error(Object error, [StackTrace stackTrace]) =>
51 new ErrorResult(error, stackTrace);
52
53 // Helper functions.
54 static _captureValue(value) => new ValueResult(value);
55 static _captureError(error, stack) => new ErrorResult(error, stack);
56 static _release(Result v) {
57 if (v.isValue) return v.asValue.value; // Avoid wrapping in future.
58 return v.asFuture;
59 }
60
61 /**
62 * Capture the result of a future into a `Result` future.
63 *
64 * The resulting future will never have an error.
65 * Errors have been converted to an [ErrorResult] value.
66 */
67 static Future<Result> capture(Future future) {
68 return future.then(_captureValue, onError: _captureError);
69 }
70
71 /**
72 * Release the result of a captured future.
73 *
74 * Converts the [Result] value of the given [future] to a result or error
75 * completion of the returned future.
76 *
77 * If [future] completes with an error, the returned future completes with
78 * the same error.
79 */
80 static Future release(Future<Result> future) {
81 return future.then(_release);
82 }
83
84 /**
85 * Capture the results of a stream into a stream of [Result] values.
86 *
87 * The returned stream will not have any error events.
88 * Errors from the source stream have been converted to [ErrorResult]s.
89 *
90 * Shorthand for transforming the stream using [CaptureStreamTransformer].
91 */
92 static Stream<Result> captureStream(Stream source) {
93 return source.transform(const CaptureStreamTransformer());
94 }
95
96 /**
97 * Release a stream of [result] values into a stream of the results.
98 *
99 * `Result` values of the source stream become value or error events in
100 * the retuned stream as appropriate.
101 * Errors from the source stream become errors in the returned stream.
102 *
103 * Shorthand for transforming the stream using [ReleaseStreamTransformer].
104 */
105 static Stream releaseStream(Stream<Result> source) {
106 return source.transform(const ReleaseStreamTransformer());
107 }
108
109 /**
110 * Whether this result is a value result.
111 *
112 * Always the opposite of [isError].
113 */
114 bool get isValue;
115
116 /**
117 * Whether this result is an error result.
118 *
119 * Always the opposite of [isValue].
120 */
121 bool get isError;
122
123 /**
124 * If this is a value result, return itself.
125 *
126 * Otherwise return `null`.
127 */
128 ValueResult<T> get asValue;
129
130 /**
131 * If this is an error result, return itself.
132 *
133 * Otherwise return `null`.
134 */
135 ErrorResult get asError;
136
137 /**
138 * Complete a completer with this result.
139 */
140 void complete(Completer<T> completer);
141
142 /**
143 * Add this result to a [StreamSink].
144 */
145 void addTo(EventSink<T> sink);
146
147 /**
148 * Creates a future completed with this result as a value or an error.
149 */
150 Future<T> get asFuture;
151 }
152
153 /**
154 * A result representing a returned value.
155 */
156 class ValueResult<T> implements Result<T> {
157 /** The returned value that this result represents. */
158 final T value;
159 /** Create a value result with the given [value]. */
160 ValueResult(this.value);
161 bool get isValue => true;
162 bool get isError => false;
163 ValueResult<T> get asValue => this;
164 ErrorResult get asError => null;
165 void complete(Completer<T> completer) {
166 completer.complete(value);
167 }
168 void addTo(EventSink<T> sink) {
169 sink.add(value);
170 }
171 Future<T> get asFuture => new Future.value(value);
172 }
173
174 /**
175 * A result representing a thrown error.
176 */
177 class ErrorResult implements Result {
178 /** The thrown object that this result represents. */
179 final error;
180 /** The stack trace, if any, associated with the throw. */
181 final StackTrace stackTrace;
182 /** Create an error result with the given [error] and [stackTrace]. */
183 ErrorResult(this.error, this.stackTrace);
184 bool get isValue => false;
185 bool get isError => true;
186 ValueResult get asValue => null;
187 ErrorResult get asError => this;
188 void complete(Completer<T> completer) {
189 completer.completeError(error, stackTrace);
190 }
191 void addTo(EventSink<T> sink) {
192 sink.addError(error, stackTrace);
193 }
194 Future get asFuture => new Future.error(error, stackTrace);
195 }
196
197 /**
198 * A stream transformer that captures a stream of events into [Result]s.
199 *
200 * The result of the transformation is a stream of [Result] values and
201 * no error events.
202 */
203 class CaptureStreamTransformer<T> implements StreamTransformer<T, Result<T>> {
204 const CaptureStreamTransformer();
205
206 Stream<Result<T>> bind(Stream<T> source) {
207 return new Stream<Result<T>>.eventTransformed(source, _createSink);
208 }
209
210 static EventSink _createSink(EventSink<Result> sink) {
211 return new CaptureSink(sink);
212 }
213 }
214
215 /**
216 * A stream transformer that releases a stream of result events.
217 *
218 * The result of the transformation is a stream of values and
219 * error events.
220 */
221 class ReleaseStreamTransformer<T> implements StreamTransformer<Result<T>, T> {
222 const ReleaseStreamTransformer();
223
224 Stream<T> bind(Stream<Result<T>> source) {
225 return new Stream<T>.eventTransformed(source, _createSink);
226 }
227
228 static EventSink _createSink(EventSink<Result> sink) {
229 return new ReleaseSink(sink);
230 }
231 }
232
233 /**
234 * An event sink wrapper that captures the incoming events.
235 *
236 * Wraps an [EventSink] that expects [Result] values.
237 * Accepts any value and error result,
238 * and passes them to the wrapped sink as [Result] values.
239 *
240 * The wrapped sink will never receive an error event.
241 */
242 class CaptureSink<T> implements EventSink<T> {
243 final EventSink _sink;
244
245 CaptureSink(EventSink<Result<T>> sink) : _sink = sink;
246 void add(T value) { _sink.add(new ValueResult(value)); }
247 void addError(Object error, StackTrace stackTrace) {
248 _sink.add(new ErrorResult(error, stackTrace));
249 }
250 void close() { _sink.close(); }
251 }
252
253 /**
254 * An event sink wrapper that releases the incoming result events.
255 *
256 * Wraps an output [EventSink] that expects any result.
257 * Accepts [Result] values, and puts the result value or error into the
258 * corresponding output sink add method.
259 */
260 class ReleaseSink<T> implements EventSink<Result<T>> {
261 final EventSink _sink;
262 ReleaseSink(EventSink<T> sink) : _sink = sink;
263 void add(Result<T> result) {
264 if (result.isValue) {
265 _sink.add(result.asValue.value);
266 } else {
267 ErrorResult error = result.asError;
268 _sink.addError(error.error, error.stackTrace);
269 }
270 }
271 void addError(Object error, StackTrace stackTrace) {
272 // Errors may be added by intermediate processing, even if it is never
273 // added by CaptureSink.
274 _sink.addError(error, stackTrace);
275 }
276
277 void close() { _sink.close(); }
278 }
OLDNEW
« no previous file with comments | « pkg/async/lib/async.dart ('k') | pkg/async/pubspec.yaml » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698