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