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

Side by Side Diff: pkg/scheduled_test/lib/src/utils.dart

Issue 812253002: Delete a bunch of packages that are now on GitHub. (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Un-delete http Created 6 years 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/scheduled_test/lib/src/task.dart ('k') | pkg/scheduled_test/lib/src/value_future.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) 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 library utils;
6
7 import 'dart:async';
8
9 import 'package:stack_trace/stack_trace.dart';
10
11 /// A pair of values.
12 class Pair<E, F> {
13 E first;
14 F last;
15
16 Pair(this.first, this.last);
17
18 String toString() => '($first, $last)';
19
20 bool operator ==(other) {
21 if (other is! Pair) return false;
22 return other.first == first && other.last == last;
23 }
24
25 int get hashCode => first.hashCode ^ last.hashCode;
26 }
27
28 /// A class that represents a value or an error.
29 class Fallible<E> {
30 /// Whether [this] has a [value], as opposed to an [error].
31 final bool hasValue;
32
33 /// Whether [this] has an [error], as opposed to a [value].
34 bool get hasError => !hasValue;
35
36 /// The value.
37 ///
38 /// This will be `null` if [this] has an [error].
39 final E _value;
40
41 /// The value.
42 ///
43 /// This will throw a [StateError] if [this] has an [error].
44 E get value {
45 if (hasValue) return _value;
46 throw new StateError("Fallible has no value.\n"
47 "$_error$_stackTraceSuffix");
48 }
49
50 /// The error.
51 ///
52 /// This will be `null` if [this] has a [value].
53 final _error;
54
55 /// The error.
56 ///
57 /// This will throw a [StateError] if [this] has a [value].
58 get error {
59 if (hasError) return _error;
60 throw new StateError("Fallible has no error.");
61 }
62
63 /// The stack trace for [_error].
64 ///
65 /// This will be `null` if [this] has a [value], or if no stack trace was
66 /// provided.
67 final StackTrace _stackTrace;
68
69 /// The stack trace for [error].
70 ///
71 /// This will throw a [StateError] if [this] has a [value].
72 StackTrace get stackTrace {
73 if (hasError) return _stackTrace;
74 throw new StateError("Fallible has no error.");
75 }
76
77 Fallible.withValue(this._value)
78 : _error = null,
79 _stackTrace = null,
80 hasValue = true;
81
82 Fallible.withError(this._error, [this._stackTrace])
83 : _value = null,
84 hasValue = false;
85
86 /// Returns a completed Future with the same value or error as [this].
87 Future toFuture() {
88 if (hasValue) return new Future.value(value);
89 return new Future.error(error, stackTrace);
90 }
91
92 String toString() {
93 if (hasValue) return "Fallible value: $value";
94 return "Fallible error: $error$_stackTraceSuffix";
95 }
96
97 String get _stackTraceSuffix {
98 if (stackTrace == null) return "";
99 return "\nStack trace:\n${new Chain.forTrace(_stackTrace).terse}";
100 }
101 }
102
103 /// Configures [future] so that its result (success or exception) is passed on
104 /// to [completer].
105 void chainToCompleter(Future future, Completer completer) {
106 future.then(completer.complete, onError: completer.completeError);
107 }
108
109 /// Like [Future.sync], but wraps the Future in [Chain.track] as well.
110 Future syncFuture(callback()) => Chain.track(new Future.sync(callback));
111
112 /// Prepends each line in [text] with [prefix]. If [firstPrefix] is passed, the
113 /// first line is prefixed with that instead.
114 String prefixLines(String text, {String prefix: '| ', String firstPrefix}) {
115 var lines = text.split('\n');
116 if (firstPrefix == null) {
117 return lines.map((line) => '$prefix$line').join('\n');
118 }
119
120 var firstLine = "$firstPrefix${lines.first}";
121 lines = lines.skip(1).map((line) => '$prefix$line').toList();
122 lines.insert(0, firstLine);
123 return lines.join('\n');
124 }
125
126 /// Returns a [Future] that completes after pumping the event queue [times]
127 /// times. By default, this should pump the event queue enough times to allow
128 /// any code to run, as long as it's not waiting on some external event.
129 Future pumpEventQueue([int times = 20]) {
130 if (times == 0) return new Future.value();
131 // We use a delayed future to allow microtask events to finish. The
132 // Future.value or Future() constructors use scheduleMicrotask themselves and
133 // would therefore not wait for microtask callbacks that are scheduled after
134 // invoking this method.
135 return new Future.delayed(Duration.ZERO, () => pumpEventQueue(times - 1));
136 }
137
138 /// Returns whether [iterable1] has the same elements in the same order as
139 /// [iterable2]. The elements are compared using `==`.
140 bool orderedIterableEquals(Iterable iterable1, Iterable iterable2) {
141 var iter1 = iterable1.iterator;
142 var iter2 = iterable2.iterator;
143
144 while (true) {
145 var hasNext1 = iter1.moveNext();
146 var hasNext2 = iter2.moveNext();
147 if (hasNext1 != hasNext2) return false;
148 if (!hasNext1) return true;
149 if (iter1.current != iter2.current) return false;
150 }
151 }
152
153 /// Returns a buffered stream that will emit the same values as the stream
154 /// returned by [future] once [future] completes.
155 ///
156 /// If [future] completes to an error, the return value will emit that error and
157 /// then close.
158 ///
159 /// If [broadcast] is true, a broadcast stream is returned. This assumes that
160 /// the stream returned by [future] will be a broadcast stream as well.
161 /// [broadcast] defaults to false.
162 Stream futureStream(Future<Stream> future, {bool broadcast: false}) {
163 var subscription;
164 var controller;
165
166 future = future.catchError((e, stackTrace) {
167 // Since [controller] is synchronous, it's likely that emitting an error
168 // will cause it to be cancelled before we call close.
169 if (controller != null) controller.addError(e, stackTrace);
170 if (controller != null) controller.close();
171 controller = null;
172 });
173
174 onListen() {
175 future.then((stream) {
176 if (controller == null) return;
177 subscription = stream.listen(
178 controller.add,
179 onError: controller.addError,
180 onDone: controller.close);
181 });
182 }
183
184 onCancel() {
185 if (subscription != null) subscription.cancel();
186 subscription = null;
187 controller = null;
188 }
189
190 if (broadcast) {
191 controller = new StreamController.broadcast(
192 sync: true, onListen: onListen, onCancel: onCancel);
193 } else {
194 controller = new StreamController(
195 sync: true, onListen: onListen, onCancel: onCancel);
196 }
197 return controller.stream;
198 }
199
200 /// Returns the first element of a [StreamIterator].
201 ///
202 /// If the [StreamIterator] has no elements, the result is a state error.
203 Future<String> streamIteratorFirst(StreamIterator<String> streamIterator) {
204 return streamIterator.moveNext().then((hasNext) {
205 if (hasNext) {
206 return streamIterator.current;
207 } else {
208 throw new StateError("No elements");
209 }
210 });
211 }
212
213 /// Collects all remaining lines from a [StreamIterator] of lines.
214 ///
215 /// Returns the concatenation of the collected lines joined by newlines.
216 Future<String> concatRest(StreamIterator<String> streamIterator) {
217 var completer = new Completer<String>();
218 var buffer = new StringBuffer();
219 void collectAll() {
220 streamIterator.moveNext().then((hasNext) {
221 if (hasNext) {
222 if (!buffer.isEmpty) buffer.write('\n');
223 buffer.write(streamIterator.current);
224 collectAll();
225 } else {
226 completer.complete(buffer.toString());
227 }
228 }, onError: completer.completeError);
229 }
230 collectAll();
231 return completer.future;
232 }
233
234 /// A function that can be called to cancel a [Stream] and send a done message.
235 typedef void StreamCanceller();
236
237 // TODO(nweiz): use a StreamSubscription when issue 9026 is fixed.
238 /// Returns a wrapped version of [stream] along with a function that will cancel
239 /// the wrapped stream. Unlike [StreamSubscription], this canceller will send a
240 /// "done" message to the wrapped stream.
241 Pair<Stream, StreamCanceller> streamWithCanceller(Stream stream) {
242 var controller =
243 stream.isBroadcast ? new StreamController.broadcast(sync: true)
244 : new StreamController(sync: true);
245 var controllerStream = controller.stream;
246 var subscription = stream.listen((value) {
247 if (!controller.isClosed) controller.add(value);
248 }, onError: (error, [stackTrace]) {
249 if (!controller.isClosed) controller.addError(error, stackTrace);
250 }, onDone: controller.close);
251 return new Pair<Stream, StreamCanceller>(controllerStream, controller.close);
252 }
253
254 // TODO(nweiz): remove this when issue 7787 is fixed.
255 /// Creates two single-subscription [Stream]s that each emit all values and
256 /// errors from [stream]. This is useful if [stream] is single-subscription but
257 /// multiple subscribers are necessary.
258 Pair<Stream, Stream> tee(Stream stream) {
259 var controller1 = new StreamController(sync: true);
260 var controller2 = new StreamController(sync: true);
261 stream.listen((value) {
262 controller1.add(value);
263 controller2.add(value);
264 }, onError: (error, [stackTrace]) {
265 controller1.addError(error, stackTrace);
266 controller2.addError(error, stackTrace);
267 }, onDone: () {
268 controller1.close();
269 controller2.close();
270 });
271 return new Pair<Stream, Stream>(controller1.stream, controller2.stream);
272 }
273
274 /// Takes a simple data structure (composed of [Map]s, [Iterable]s, scalar
275 /// objects, and [Future]s) and recursively resolves all the [Future]s contained
276 /// within. Completes with the fully resolved structure.
277 Future awaitObject(object) {
278 // Unroll nested futures.
279 if (object is Future) return object.then(awaitObject);
280 if (object is Iterable) {
281 return Future.wait(object.map(awaitObject).toList());
282 }
283 if (object is! Map) return new Future.value(object);
284
285 var pairs = <Future<Pair>>[];
286 object.forEach((key, value) {
287 pairs.add(awaitObject(value)
288 .then((resolved) => new Pair(key, resolved)));
289 });
290 return Future.wait(pairs).then((resolvedPairs) {
291 var map = {};
292 for (var pair in resolvedPairs) {
293 map[pair.first] = pair.last;
294 }
295 return map;
296 });
297 }
298
299 /// Returns whether [pattern] matches all of [string].
300 bool fullMatch(String string, Pattern pattern) {
301 var matches = pattern.allMatches(string);
302 if (matches.isEmpty) return false;
303 return matches.first.start == 0 && matches.first.end == string.length;
304 }
305
306 /// Returns a string representation of [trace] that has the core and test frames
307 /// folded together.
308 String terseTraceString(StackTrace trace) {
309 return new Chain.forTrace(trace).terse.toString().trim();
310 }
OLDNEW
« no previous file with comments | « pkg/scheduled_test/lib/src/task.dart ('k') | pkg/scheduled_test/lib/src/value_future.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698