Add methods to Result. Bump version to 2.0 and remove deprecated features.
R=floitsch@google.com
Review-Url: https://codereview.chromium.org//2996143002 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e4a8696..a1e9683 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,12 @@
+## 2.0.0
+* Remove deprecated public `result.dart` and `stream_zip.dart` libraries and
+ deprecated classes `ReleaseStreamTransformer` and `CaptureStreamTransformer`.
+
+* Add `captureAll` and `flattenList` static methods to `Result`.
+
+* Change `ErrorResult` to not be generic and always be a `Result<Null>`.
+ That makes an error independent of the type of result it occurs instead of.
+
## 1.13.3
* Make `TypeSafeStream` extend `Stream` instead of implementing it. This ensures
diff --git a/lib/async.dart b/lib/async.dart
index e090032..25fc0fd 100644
--- a/lib/async.dart
+++ b/lib/async.dart
@@ -17,11 +17,9 @@
export "src/lazy_stream.dart";
export "src/null_stream_sink.dart";
export "src/restartable_timer.dart";
-export "src/result.dart";
-export "src/result/capture_transformer.dart";
+export "src/result/result.dart";
export "src/result/error.dart";
export "src/result/future.dart";
-export "src/result/release_transformer.dart";
export "src/result/value.dart";
export "src/single_subscription_transformer.dart";
export "src/stream_completer.dart";
diff --git a/lib/result.dart b/lib/result.dart
deleted file mode 100644
index 627f200..0000000
--- a/lib/result.dart
+++ /dev/null
@@ -1,13 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/// Import `async.dart` instead.
-@Deprecated("Will be removed in async 2.0.0.")
-library dart.pkg.async.results;
-
-export "src/result.dart";
-export "src/result/capture_transformer.dart";
-export "src/result/error.dart";
-export "src/result/release_transformer.dart";
-export "src/result/value.dart";
diff --git a/lib/src/result.dart b/lib/src/result.dart
deleted file mode 100644
index 49457c3..0000000
--- a/lib/src/result.dart
+++ /dev/null
@@ -1,150 +0,0 @@
-// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import 'dart:async';
-
-import 'result/capture_transformer.dart';
-import 'result/error.dart';
-import 'result/release_transformer.dart';
-import 'result/value.dart';
-import 'stream_sink_transformer.dart';
-
-/// The result of a computation.
-///
-/// Capturing a result (either a returned value or a thrown error) means
-/// converting it into a [Result] - either a [ValueResult] or an [ErrorResult].
-///
-/// This value can release itself by writing itself either to a [EventSink] or a
-/// [Completer], or by becoming a [Future].
-abstract class Result<T> {
- /// A stream transformer that captures a stream of events into [Result]s.
- ///
- /// The result of the transformation is a stream of [Result] values and no
- /// error events. This is the transformer used by [captureStream].
- static const StreamTransformer<Object, Result> captureStreamTransformer =
- const CaptureStreamTransformer();
-
- /// A stream transformer that releases a stream of result events.
- ///
- /// The result of the transformation is a stream of values and error events.
- /// This is the transformer used by [releaseStream].
- static const StreamTransformer<Object, Result> releaseStreamTransformer =
- const ReleaseStreamTransformer();
-
- /// A sink transformer that captures events into [Result]s.
- ///
- /// The result of the transformation is a sink that only forwards [Result]
- /// values and no error events.
- static const StreamSinkTransformer<Object, Result> captureSinkTransformer =
- const StreamSinkTransformer.fromStreamTransformer(
- const CaptureStreamTransformer());
-
- /// A sink transformer that releases result events.
- ///
- /// The result of the transformation is a sink that forwards of values and
- /// error events.
- static const StreamSinkTransformer<Object, Result> releaseSinkTransformer =
- const StreamSinkTransformer.fromStreamTransformer(
- const ReleaseStreamTransformer());
-
- /// Create a `Result` with the result of calling [computation].
- ///
- /// This generates either a [ValueResult] with the value returned by
- /// calling `computation`, or an [ErrorResult] with an error thrown by
- /// the call.
- factory Result(T computation()) {
- try {
- return new ValueResult(computation());
- } catch (e, s) {
- return new ErrorResult(e, s);
- }
- }
-
- /// Create a `Result` holding a value.
- ///
- /// Alias for [ValueResult.ValueResult].
- factory Result.value(T value) = ValueResult<T>;
-
- /// Create a `Result` holding an error.
- ///
- /// Alias for [ErrorResult.ErrorResult].
- factory Result.error(Object error, [StackTrace stackTrace]) =>
- new ErrorResult(error, stackTrace);
-
- /// Capture the result of a future into a `Result` future.
- ///
- /// The resulting future will never have an error.
- /// Errors have been converted to an [ErrorResult] value.
- static Future<Result<T>> capture<T>(Future<T> future) {
- return future.then((value) => new ValueResult(value),
- onError: (error, stackTrace) => new ErrorResult<T>(error, stackTrace));
- }
-
- /// Release the result of a captured future.
- ///
- /// Converts the [Result] value of the given [future] to a value or error
- /// completion of the returned future.
- ///
- /// If [future] completes with an error, the returned future completes with
- /// the same error.
- static Future<T> release<T>(Future<Result<T>> future) =>
- future.then<T>((result) => result.asFuture);
-
- /// Capture the results of a stream into a stream of [Result] values.
- ///
- /// The returned stream will not have any error events.
- /// Errors from the source stream have been converted to [ErrorResult]s.
- static Stream<Result<T>> captureStream<T>(Stream<T> source) =>
- source.transform(new CaptureStreamTransformer<T>());
-
- /// Release a stream of [result] values into a stream of the results.
- ///
- /// `Result` values of the source stream become value or error events in
- /// the returned stream as appropriate.
- /// Errors from the source stream become errors in the returned stream.
- static Stream<T> releaseStream<T>(Stream<Result<T>> source) =>
- source.transform(new ReleaseStreamTransformer<T>());
-
- /// Converts a result of a result to a single result.
- ///
- /// If the result is an error, or it is a `Result` value
- /// which is then an error, then a result with that error is returned.
- /// Otherwise both levels of results are value results, and a single
- /// result with the value is returned.
- static Result<T> flatten<T>(Result<Result<T>> result) {
- if (result.isValue) return result.asValue.value;
- return new ErrorResult<T>(result.asError.error, result.asError.stackTrace);
- }
-
- /// Whether this result is a value result.
- ///
- /// Always the opposite of [isError].
- bool get isValue;
-
- /// Whether this result is an error result.
- ///
- /// Always the opposite of [isValue].
- bool get isError;
-
- /// If this is a value result, return itself.
- ///
- /// Otherwise return `null`.
- ValueResult<T> get asValue;
-
- /// If this is an error result, return itself.
- ///
- /// Otherwise return `null`.
- ErrorResult<T> get asError;
-
- /// Complete a completer with this result.
- void complete(Completer<T> completer);
-
- /// Add this result to an [EventSink].
- ///
- /// Calls the sink's `add` or `addError` method as appropriate.
- void addTo(EventSink<T> sink);
-
- /// Creates a future completed with this result as a value or an error.
- Future<T> get asFuture;
-}
diff --git a/lib/src/result/capture_sink.dart b/lib/src/result/capture_sink.dart
index 7474525..c85b553 100644
--- a/lib/src/result/capture_sink.dart
+++ b/lib/src/result/capture_sink.dart
@@ -4,12 +4,11 @@
import 'dart:async';
-import '../result.dart';
+import 'result.dart';
-/// Use [Result.captureSinkTransformer].
-@Deprecated("Will be removed in async 2.0.0.")
+/// Used by [Result.captureSink].
class CaptureSink<T> implements EventSink<T> {
- final EventSink _sink;
+ final EventSink<Result<T>> _sink;
CaptureSink(EventSink<Result<T>> sink) : _sink = sink;
diff --git a/lib/src/result/capture_transformer.dart b/lib/src/result/capture_transformer.dart
index 6b1bbf2..71e8a00 100644
--- a/lib/src/result/capture_transformer.dart
+++ b/lib/src/result/capture_transformer.dart
@@ -4,14 +4,13 @@
import 'dart:async';
-import '../result.dart';
+import 'result.dart';
import 'capture_sink.dart';
/// A stream transformer that captures a stream of events into [Result]s.
///
/// The result of the transformation is a stream of [Result] values and no
-/// error events. This is the transformer used by [captureStream].
-@Deprecated("Will be removed in async 2.0.0.")
+/// error events. Exposed by [Result.captureStream].
class CaptureStreamTransformer<T> implements StreamTransformer<T, Result<T>> {
const CaptureStreamTransformer();
@@ -19,7 +18,6 @@
return new Stream<Result<T>>.eventTransformed(source, _createSink);
}
- static EventSink _createSink(EventSink<Result> sink) {
- return new CaptureSink(sink);
- }
+ // Since Stream.eventTransformed is not generic, this method can be static.
+ static EventSink _createSink(EventSink<Result> sink) => new CaptureSink(sink);
}
diff --git a/lib/src/result/error.dart b/lib/src/result/error.dart
index b6d5859..45e06a2 100644
--- a/lib/src/result/error.dart
+++ b/lib/src/result/error.dart
@@ -4,18 +4,21 @@
import 'dart:async';
-import '../result.dart';
+import 'result.dart';
import 'value.dart';
/// A result representing a thrown error.
-class ErrorResult<T> implements Result<T> {
+class ErrorResult implements Result<Null> {
+ /// The error object that was thrown.
final error;
+
+ /// The stack trace corresponding to where [error] was thrown.
final StackTrace stackTrace;
bool get isValue => false;
bool get isError => true;
- ValueResult<T> get asValue => null;
- ErrorResult<T> get asError => this;
+ ValueResult<Null> get asValue => null;
+ ErrorResult get asError => this;
ErrorResult(this.error, this.stackTrace);
@@ -27,7 +30,7 @@
sink.addError(error, stackTrace);
}
- Future<T> get asFuture => new Future.error(error, stackTrace);
+ Future<Null> get asFuture => new Future<Null>.error(error, stackTrace);
/// Calls an error handler with the error and stacktrace.
///
@@ -42,4 +45,12 @@
errorHandler(error);
}
}
+
+ int get hashCode => error.hashCode ^ stackTrace.hashCode ^ 0x1d61823f;
+
+ /// This is equal only to an error result with equal [error] and [stackTrace].
+ bool operator ==(Object other) =>
+ other is ErrorResult &&
+ error == other.error &&
+ stackTrace == other.stackTrace;
}
diff --git a/lib/src/result/future.dart b/lib/src/result/future.dart
index 749b101..ff30546 100644
--- a/lib/src/result/future.dart
+++ b/lib/src/result/future.dart
@@ -5,7 +5,7 @@
import 'dart:async';
import '../delegate/future.dart';
-import '../result.dart';
+import 'result.dart';
/// A [Future] wrapper that provides synchronous access to the result of the
/// wrapped [Future] once it's completed.
@@ -19,15 +19,9 @@
Result<T> get result => _result;
Result<T> _result;
- factory ResultFuture(Future<T> future) {
- ResultFuture<T> resultFuture;
- resultFuture = new ResultFuture._(() async {
- var result = await Result.capture(future);
- resultFuture._result = result;
- return await result.asFuture;
- }());
- return resultFuture;
+ ResultFuture(Future<T> future) : super(future) {
+ Result.capture(future).then((result) {
+ _result = result;
+ });
}
-
- ResultFuture._(Future<T> future) : super(future);
}
diff --git a/lib/src/result/release_sink.dart b/lib/src/result/release_sink.dart
index 114981b..a0715a1 100644
--- a/lib/src/result/release_sink.dart
+++ b/lib/src/result/release_sink.dart
@@ -4,22 +4,16 @@
import 'dart:async';
-import '../result.dart';
+import 'result.dart';
-/// Use [Result.captureSinkTransformer].
-@Deprecated("Will be removed in async 2.0.0.")
+/// Used by [Result.releaseSink].
class ReleaseSink<T> implements EventSink<Result<T>> {
final EventSink _sink;
ReleaseSink(EventSink<T> sink) : _sink = sink;
void add(Result<T> result) {
- if (result.isValue) {
- _sink.add(result.asValue.value);
- } else {
- var error = result.asError;
- _sink.addError(error.error, error.stackTrace);
- }
+ result.addTo(_sink);
}
void addError(Object error, [StackTrace stackTrace]) {
diff --git a/lib/src/result/release_transformer.dart b/lib/src/result/release_transformer.dart
index 456ed0a..fc9278d 100644
--- a/lib/src/result/release_transformer.dart
+++ b/lib/src/result/release_transformer.dart
@@ -4,11 +4,10 @@
import 'dart:async';
-import '../result.dart';
+import 'result.dart';
import 'release_sink.dart';
-/// Use [Result.releaseTransformer] instead.
-@Deprecated("Will be removed in async 2.0.0.")
+/// A transformer that releases result events as data and error events.
class ReleaseStreamTransformer<T> implements StreamTransformer<Result<T>, T> {
const ReleaseStreamTransformer();
@@ -16,7 +15,6 @@
return new Stream<T>.eventTransformed(source, _createSink);
}
- static EventSink<Result> _createSink(EventSink sink) {
- return new ReleaseSink(sink);
- }
+ // Since Stream.eventTransformed is not generic, this method can be static.
+ static EventSink<Result> _createSink(EventSink sink) => new ReleaseSink(sink);
}
diff --git a/lib/src/result/result.dart b/lib/src/result/result.dart
new file mode 100644
index 0000000..98b5aa4
--- /dev/null
+++ b/lib/src/result/result.dart
@@ -0,0 +1,224 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import 'dart:async';
+
+import 'capture_sink.dart';
+import 'capture_transformer.dart';
+import 'error.dart';
+import 'release_sink.dart';
+import 'release_transformer.dart';
+import 'value.dart';
+import '../stream_sink_transformer.dart';
+
+/// The result of a computation.
+///
+/// Capturing a result (either a returned value or a thrown error) means
+/// converting it into a [Result] - either a [ValueResult] or an [ErrorResult].
+///
+/// This value can release itself by writing itself either to a [EventSink] or a
+/// [Completer], or by becoming a [Future].
+///
+/// A [Future] represents a potential result, one that might not have been
+/// computed yet, and a [Result] is always a completed and available result.
+abstract class Result<T> {
+ /// A stream transformer that captures a stream of events into [Result]s.
+ ///
+ /// The result of the transformation is a stream of [Result] values and no
+ /// error events. This is the transformer used by [captureStream].
+ static const StreamTransformer<Object, Result<Object>>
+ captureStreamTransformer = const CaptureStreamTransformer<Object>();
+
+ /// A stream transformer that releases a stream of result events.
+ ///
+ /// The result of the transformation is a stream of values and error events.
+ /// This is the transformer used by [releaseStream].
+ static const StreamTransformer<Result<Object>, Object>
+ releaseStreamTransformer = const ReleaseStreamTransformer<Object>();
+
+ /// A sink transformer that captures events into [Result]s.
+ ///
+ /// The result of the transformation is a sink that only forwards [Result]
+ /// values and no error events.
+ static const StreamSinkTransformer<Object, Result<Object>>
+ captureSinkTransformer =
+ const StreamSinkTransformer<Object, Result<Object>>.fromStreamTransformer(
+ const CaptureStreamTransformer<Object>());
+
+ /// A sink transformer that releases result events.
+ ///
+ /// The result of the transformation is a sink that forwards of values and
+ /// error events.
+ static const StreamSinkTransformer<Result<Object>, Object>
+ releaseSinkTransformer =
+ const StreamSinkTransformer<Result<Object>, Object>.fromStreamTransformer(
+ const ReleaseStreamTransformer<Object>());
+
+ /// Creates a `Result` with the result of calling [computation].
+ ///
+ /// This generates either a [ValueResult] with the value returned by
+ /// calling `computation`, or an [ErrorResult] with an error thrown by
+ /// the call.
+ factory Result(T computation()) {
+ try {
+ return new ValueResult<T>(computation());
+ } catch (e, s) {
+ return new ErrorResult(e, s);
+ }
+ }
+
+ /// Creates a `Result` holding a value.
+ ///
+ /// Alias for [ValueResult.ValueResult].
+ factory Result.value(T value) = ValueResult<T>;
+
+ /// Creates a `Result` holding an error.
+ ///
+ /// Alias for [ErrorResult.ErrorResult].
+ factory Result.error(Object error, [StackTrace stackTrace]) =>
+ new ErrorResult(error, stackTrace);
+
+ /// Captures the result of a future into a `Result` future.
+ ///
+ /// The resulting future will never have an error.
+ /// Errors have been converted to an [ErrorResult] value.
+ static Future<Result<T>> capture<T>(Future<T> future) {
+ return future.then((value) => new ValueResult(value),
+ onError: (error, stackTrace) => new ErrorResult(error, stackTrace));
+ }
+
+ /// Captures each future in [elements],
+ ///
+ /// Returns a (future of) a list of results for each element in [elements],
+ /// in iteration order.
+ /// Each future in [elements] is [capture]d and each non-future is
+ /// wrapped as a [Result.value].
+ /// The returned future will never have an error.
+ static Future<List<Result<T>>> captureAll<T>(Iterable<FutureOr<T>> elements) {
+ var results = <Result<T>>[];
+ int pending = 0;
+ var completer;
+ for (var element in elements) {
+ if (element is Future<T>) {
+ int i = results.length;
+ results.add(null);
+ pending++;
+ Result.capture<T>(element).then((result) {
+ results[i] = result;
+ if (--pending == 0) {
+ completer.complete(results);
+ }
+ });
+ } else {
+ results.add(new Result<T>.value(element));
+ }
+ }
+ if (pending == 0) {
+ return new Future<List<Result<T>>>.value(results);
+ }
+ completer = new Completer<List<Result<T>>>();
+ return completer.future;
+ }
+
+ /// Releases the result of a captured future.
+ ///
+ /// Converts the [Result] value of the given [future] to a value or error
+ /// completion of the returned future.
+ ///
+ /// If [future] completes with an error, the returned future completes with
+ /// the same error.
+ static Future<T> release<T>(Future<Result<T>> future) =>
+ future.then<T>((result) => result.asFuture);
+
+ /// Captures the results of a stream into a stream of [Result] values.
+ ///
+ /// The returned stream will not have any error events.
+ /// Errors from the source stream have been converted to [ErrorResult]s.
+ static Stream<Result<T>> captureStream<T>(Stream<T> source) =>
+ source.transform(new CaptureStreamTransformer<T>());
+
+ /// Releases a stream of [result] values into a stream of the results.
+ ///
+ /// `Result` values of the source stream become value or error events in
+ /// the returned stream as appropriate.
+ /// Errors from the source stream become errors in the returned stream.
+ static Stream<T> releaseStream<T>(Stream<Result<T>> source) =>
+ source.transform(new ReleaseStreamTransformer<T>());
+
+ /// Releases results added to the returned sink as data and errors on [sink].
+ ///
+ /// A [Result] added to the returned sink is added as a data or error event
+ /// on [sink]. Errors added to the returned sink are forwarded directly to
+ /// [sink] and so is the [EventSink.close] calls.
+ static EventSink<Result<T>> releaseSink<T>(EventSink<T> sink) =>
+ new ReleaseSink<T>(sink);
+
+ /// Captures the events of the returned sink into results on [sink].
+ ///
+ /// Data and error events added to the returned sink are captured into
+ /// [Result] values and added as data events on the provided [sink].
+ /// No error events are ever added to [sink].
+ ///
+ /// When the returned sink is closed, so is [sink].
+ static EventSink<T> captureSink<T>(EventSink<Result<T>> sink) =>
+ new CaptureSink<T>(sink);
+
+ /// Converts a result of a result to a single result.
+ ///
+ /// If the result is an error, or it is a `Result` value
+ /// which is then an error, then a result with that error is returned.
+ /// Otherwise both levels of results are value results, and a single
+ /// result with the value is returned.
+ static Result<T> flatten<T>(Result<Result<T>> result) {
+ if (result.isValue) return result.asValue.value;
+ return result.asError;
+ }
+
+ /// Converts a sequence of results to a result of a list.
+ ///
+ /// Returns either a list of values if [results] doesn't contain any errors,
+ /// or the first error result in [results].
+ static Result<List<T>> flattenAll<T>(Iterable<Result<T>> results) {
+ var values = <T>[];
+ for (var result in results) {
+ if (result.isValue) {
+ values.add(result.asValue.value);
+ } else {
+ return result.asError;
+ }
+ }
+ return new Result<List<T>>.value(values);
+ }
+
+ /// Whether this result is a value result.
+ ///
+ /// Always the opposite of [isError].
+ bool get isValue;
+
+ /// Whether this result is an error result.
+ ///
+ /// Always the opposite of [isValue].
+ bool get isError;
+
+ /// If this is a value result, returns itself.
+ ///
+ /// Otherwise returns `null`.
+ ValueResult<T> get asValue;
+
+ /// If this is an error result, returns itself.
+ ///
+ /// Otherwise returns `null`.
+ ErrorResult get asError;
+
+ /// Completes a completer with this result.
+ void complete(Completer<T> completer);
+
+ /// Adds this result to an [EventSink].
+ ///
+ /// Calls the sink's `add` or `addError` method as appropriate.
+ void addTo(EventSink<T> sink);
+
+ /// A future that has been completed with this result as a value or an error.
+ Future<T> get asFuture;
+}
diff --git a/lib/src/result/value.dart b/lib/src/result/value.dart
index 39fa048..edc41fb 100644
--- a/lib/src/result/value.dart
+++ b/lib/src/result/value.dart
@@ -4,17 +4,18 @@
import 'dart:async';
-import '../result.dart';
+import 'result.dart';
import 'error.dart';
/// A result representing a returned value.
class ValueResult<T> implements Result<T> {
+ /// The result of a successful computation.
final T value;
bool get isValue => true;
bool get isError => false;
ValueResult<T> get asValue => this;
- ErrorResult<T> get asError => null;
+ ErrorResult get asError => null;
ValueResult(this.value);
@@ -27,4 +28,9 @@
}
Future<T> get asFuture => new Future.value(value);
+
+ int get hashCode => value.hashCode ^ 0x323f1d61;
+
+ bool operator ==(Object other) =>
+ other is ValueResult && value == other.value;
}
diff --git a/lib/src/stream_queue.dart b/lib/src/stream_queue.dart
index b9023ab..1318114 100644
--- a/lib/src/stream_queue.dart
+++ b/lib/src/stream_queue.dart
@@ -8,7 +8,7 @@
import 'package:collection/collection.dart';
import "cancelable_operation.dart";
-import "result.dart";
+import "result/result.dart";
import "subscription_stream.dart";
import "stream_completer.dart";
import "stream_splitter.dart";
@@ -859,9 +859,9 @@
/// source subscription.
class _CancelRequest<T> implements _EventRequest<T> {
/// Completer for the future returned by the `cancel` call.
+ /// TODO(lrn); make this Completer<void> when that is implemented.
final _completer = new Completer();
- ///
/// When the event is completed, it needs to cancel the active subscription
/// of the `StreamQueue` object, if any.
final StreamQueue _streamQueue;
diff --git a/lib/src/stream_splitter.dart b/lib/src/stream_splitter.dart
index 6cec98c..ac4260d 100644
--- a/lib/src/stream_splitter.dart
+++ b/lib/src/stream_splitter.dart
@@ -5,7 +5,7 @@
import 'dart:async';
import 'future_group.dart';
-import 'result.dart';
+import 'result/result.dart';
/// A class that splits a single source stream into an arbitrary number of
/// (single-subscription) streams (called "branch") that emit the same events.
diff --git a/lib/stream_zip.dart b/lib/stream_zip.dart
deleted file mode 100644
index cdeb5c9..0000000
--- a/lib/stream_zip.dart
+++ /dev/null
@@ -1,9 +0,0 @@
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-/// Import `async.dart` instead.
-@Deprecated("Will be removed in async 2.0.0.")
-library dart.pkg.async.stream_zip;
-
-export "src/stream_zip.dart";
diff --git a/pubspec.yaml b/pubspec.yaml
index 2ee2505..bb41d4f 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: async
-version: 1.13.3
+version: 2.0.0
author: Dart Team <misc@dartlang.org>
description: Utility functions and classes related to the 'dart:async' library.
homepage: https://www.github.com/dart-lang/async
diff --git a/test/result/result_captureAll_test.dart b/test/result/result_captureAll_test.dart
new file mode 100644
index 0000000..172e38a
--- /dev/null
+++ b/test/result/result_captureAll_test.dart
@@ -0,0 +1,187 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async";
+import "dart:math" show Random;
+import "package:async/async.dart";
+import "package:test/test.dart";
+
+final someStack = StackTrace.current;
+Result<int> res(int n) => new Result<int>.value(n);
+Result err(n) => new ErrorResult("$n", someStack);
+
+/// Helper function creating an iterable of futures.
+Iterable<Future<int>> futures(int count, {bool throwWhen(int index)}) sync* {
+ for (int i = 0; i < count; i++) {
+ if (throwWhen != null && throwWhen(i)) {
+ yield new Future<int>.error("$i", someStack);
+ } else {
+ yield new Future<int>.value(i);
+ }
+ }
+}
+
+main() {
+ test("empty", () async {
+ var all = await Result.captureAll<int>(futures(0));
+ expect(all, []);
+ });
+
+ group("futures only,", () {
+ test("single", () async {
+ var all = await Result.captureAll<int>(futures(1));
+ expect(all, [res(0)]);
+ });
+
+ test("multiple", () async {
+ var all = await Result.captureAll<int>(futures(3));
+ expect(all, [res(0), res(1), res(2)]);
+ });
+
+ test("error only", () async {
+ var all =
+ await Result.captureAll<int>(futures(1, throwWhen: (_) => true));
+ expect(all, [err(0)]);
+ });
+
+ test("multiple error only", () async {
+ var all =
+ await Result.captureAll<int>(futures(3, throwWhen: (_) => true));
+ expect(all, [err(0), err(1), err(2)]);
+ });
+
+ test("mixed error and value", () async {
+ var all =
+ await Result.captureAll<int>(futures(4, throwWhen: (x) => x.isOdd));
+ expect(all, [res(0), err(1), res(2), err(3)]);
+ });
+
+ test("completion permutation 1-2-3", () async {
+ var cs = new List.generate(3, (_) => new Completer<int>());
+ var all = Result.captureAll<int>(cs.map((c) => c.future));
+ expect(all, completion([res(1), res(2), err(3)]));
+ await 0;
+ cs[0].complete(1);
+ await 0;
+ cs[1].complete(2);
+ await 0;
+ cs[2].completeError("3", someStack);
+ });
+
+ test("completion permutation 1-3-2", () async {
+ var cs = new List.generate(3, (_) => new Completer<int>());
+ var all = Result.captureAll<int>(cs.map((c) => c.future));
+ expect(all, completion([res(1), res(2), err(3)]));
+ await 0;
+ cs[0].complete(1);
+ await 0;
+ cs[2].completeError("3", someStack);
+ await 0;
+ cs[1].complete(2);
+ });
+
+ test("completion permutation 2-1-3", () async {
+ var cs = new List.generate(3, (_) => new Completer<int>());
+ var all = Result.captureAll<int>(cs.map((c) => c.future));
+ expect(all, completion([res(1), res(2), err(3)]));
+ await 0;
+ cs[1].complete(2);
+ await 0;
+ cs[0].complete(1);
+ await 0;
+ cs[2].completeError("3", someStack);
+ });
+
+ test("completion permutation 2-3-1", () async {
+ var cs = new List.generate(3, (_) => new Completer<int>());
+ var all = Result.captureAll<int>(cs.map((c) => c.future));
+ expect(all, completion([res(1), res(2), err(3)]));
+ await 0;
+ cs[1].complete(2);
+ await 0;
+ cs[2].completeError("3", someStack);
+ await 0;
+ cs[0].complete(1);
+ });
+
+ test("completion permutation 3-1-2", () async {
+ var cs = new List.generate(3, (_) => new Completer<int>());
+ var all = Result.captureAll<int>(cs.map((c) => c.future));
+ expect(all, completion([res(1), res(2), err(3)]));
+ await 0;
+ cs[2].completeError("3", someStack);
+ await 0;
+ cs[0].complete(1);
+ await 0;
+ cs[1].complete(2);
+ });
+
+ test("completion permutation 3-2-1", () async {
+ var cs = new List.generate(3, (_) => new Completer<int>());
+ var all = Result.captureAll<int>(cs.map((c) => c.future));
+ expect(all, completion([res(1), res(2), err(3)]));
+ await 0;
+ cs[2].completeError("3", someStack);
+ await 0;
+ cs[1].complete(2);
+ await 0;
+ cs[0].complete(1);
+ });
+
+ var seed = new Random().nextInt(0x100000000);
+ int n = 25; // max 32, otherwise rnd.nextInt(1<<n) won't work.
+ test("randomized #$n seed:${seed.toRadixString(16)}", () async {
+ var cs = new List.generate(n, (_) => new Completer<int>());
+ var all = Result.captureAll<int>(cs.map((c) => c.future));
+ var rnd = new Random(seed);
+ var throwFlags = rnd.nextInt(1 << n); // Bit-flag for throwing.
+ bool throws(index) => (throwFlags & (1 << index)) != 0;
+ var expected = new List.generate(n, (x) => throws(x) ? err(x) : res(x));
+
+ expect(all, completion(expected));
+
+ var completeFunctions = new List<Function()>.generate(n, (i) {
+ var c = cs[i];
+ return () =>
+ throws(i) ? c.completeError("$i", someStack) : c.complete(i);
+ });
+ completeFunctions.shuffle(rnd);
+ for (int i = 0; i < n; i++) {
+ await 0;
+ completeFunctions[i]();
+ }
+ });
+ });
+ group("values only,", () {
+ test("single", () async {
+ var all = await Result.captureAll<int>(<int>[1]);
+ expect(all, [res(1)]);
+ });
+ test("multiple", () async {
+ var all = await Result.captureAll<int>(<int>[1, 2, 3]);
+ expect(all, [res(1), res(2), res(3)]);
+ });
+ });
+ group("mixed futures and values,", () {
+ test("no error", () async {
+ var all = await Result.captureAll<int>(<FutureOr<int>>[
+ 1,
+ new Future<int>(() => 2),
+ 3,
+ new Future<int>.value(4),
+ ]);
+ expect(all, [res(1), res(2), res(3), res(4)]);
+ });
+ test("error", () async {
+ var all = await Result.captureAll<int>(<FutureOr<int>>[
+ 1,
+ new Future<int>(() => 2),
+ 3,
+ new Future<int>(() async => await new Future.error("4", someStack)),
+ new Future<int>.value(5)
+ ]);
+ expect(all, [res(1), res(2), res(3), err(4), res(5)]);
+ });
+ });
+}
diff --git a/test/result/result_flattenAll_test.dart b/test/result/result_flattenAll_test.dart
new file mode 100644
index 0000000..caaf668
--- /dev/null
+++ b/test/result/result_flattenAll_test.dart
@@ -0,0 +1,54 @@
+// Copyright (c) 2017, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "package:async/async.dart";
+import "package:test/test.dart";
+
+final someStack = StackTrace.current;
+Result<T> res<T>(T n) => new Result<T>.value(n);
+Result err(n) => new ErrorResult("$n", someStack);
+
+/// Helper function creating an iterable of results.
+Iterable<Result<int>> results(int count, {bool throwWhen(int index)}) sync* {
+ for (int i = 0; i < count; i++) {
+ if (throwWhen != null && throwWhen(i)) {
+ yield err(i);
+ } else {
+ yield res(i);
+ }
+ }
+}
+
+main() {
+ expectAll(result, expectation) {
+ if (expectation.isError) {
+ expect(result, expectation);
+ } else {
+ expect(result.isValue, true);
+ expect(result.asValue.value, expectation.asValue.value);
+ }
+ }
+
+ test("empty", () {
+ expectAll(Result.flattenAll<int>(results(0)), res([]));
+ });
+ test("single value", () {
+ expectAll(Result.flattenAll<int>(results(1)), res([0]));
+ });
+ test("single error", () {
+ expectAll(
+ Result.flattenAll<int>(results(1, throwWhen: (_) => true)), err(0));
+ });
+ test("multiple values", () {
+ expectAll(Result.flattenAll<int>(results(5)), res([0, 1, 2, 3, 4]));
+ });
+ test("multiple errors", () {
+ expectAll(Result.flattenAll<int>(results(5, throwWhen: (x) => x.isOdd)),
+ err(1)); // First error is result.
+ });
+ test("error last", () {
+ expectAll(
+ Result.flattenAll<int>(results(5, throwWhen: (x) => x == 4)), err(4));
+ });
+}
diff --git a/test/result_future_test.dart b/test/result/result_future_test.dart
similarity index 100%
rename from test/result_future_test.dart
rename to test/result/result_future_test.dart
diff --git a/test/result_test.dart b/test/result/result_test.dart
similarity index 100%
rename from test/result_test.dart
rename to test/result/result_test.dart