Use sync forwarders for `switchLatest` (dart-lang/stream_transform#30)
Towards dart-lang/stream_transform#24
- Don't return a Future from `onCancel` when the values were already
done.
- Use `sync: true`
- Drop unnecessary `await new Future(() {})`s
- Set onPause, onResume, and onCancel inside onListen.diff --git a/pkgs/stream_transform/lib/src/switch.dart b/pkgs/stream_transform/lib/src/switch.dart
index be9eeeb..b7fc110 100644
--- a/pkgs/stream_transform/lib/src/switch.dart
+++ b/pkgs/stream_transform/lib/src/switch.dart
@@ -32,58 +32,54 @@
@override
Stream<T> bind(Stream<Stream<T>> outer) {
- StreamController<T> controller;
- if (outer.isBroadcast) {
- controller = new StreamController<T>.broadcast();
- } else {
- controller = new StreamController<T>();
- }
- StreamSubscription<T> innerSubscription;
+ var controller = outer.isBroadcast
+ ? new StreamController<T>.broadcast(sync: true)
+ : new StreamController<T>(sync: true);
+
StreamSubscription<Stream<T>> outerSubscription;
+
controller.onListen = () {
+ if (outerSubscription != null) return;
+
+ StreamSubscription<T> innerSubscription;
var outerStreamDone = false;
- var innerStreamDone = false;
- outerSubscription = outer.listen((innerStream) {
- innerSubscription?.cancel();
- innerSubscription = innerStream.listen(controller.add);
- innerSubscription.onDone(() {
- innerStreamDone = true;
- if (outerStreamDone) {
- controller.close();
- }
- });
- innerSubscription.onError(controller.addError);
- });
- outerSubscription.onDone(() {
- outerStreamDone = true;
- if (innerStreamDone) {
- controller.close();
- }
- });
- outerSubscription.onError(controller.addError);
- };
- cancelSubscriptions() => Future.wait([
- innerSubscription?.cancel() ?? new Future.value(),
- outerSubscription?.cancel() ?? new Future.value()
- ]);
-
- if (!outer.isBroadcast) {
- controller.onPause = () {
- innerSubscription?.pause();
- outerSubscription?.pause();
- };
- controller.onResume = () {
- innerSubscription?.resume();
- outerSubscription?.resume();
- };
- controller.onCancel = () => cancelSubscriptions();
- } else {
+ outerSubscription = outer.listen(
+ (innerStream) {
+ innerSubscription?.cancel();
+ innerSubscription = innerStream.listen(controller.add,
+ onError: controller.addError, onDone: () {
+ innerSubscription = null;
+ if (outerStreamDone) controller.close();
+ });
+ },
+ onError: controller.addError,
+ onDone: () {
+ outerStreamDone = true;
+ if (innerSubscription == null) controller.close();
+ });
+ if (!outer.isBroadcast) {
+ controller.onPause = () {
+ innerSubscription?.pause();
+ outerSubscription.pause();
+ };
+ controller.onResume = () {
+ innerSubscription?.resume();
+ outerSubscription.resume();
+ };
+ }
controller.onCancel = () {
- if (controller.hasListener) return new Future.value();
- return cancelSubscriptions();
+ var toCancel = <StreamSubscription>[];
+ if (!outerStreamDone) toCancel.add(outerSubscription);
+ if (innerSubscription != null) {
+ toCancel.add(innerSubscription);
+ }
+ outerSubscription = null;
+ innerSubscription = null;
+ if (toCancel.isEmpty) return null;
+ return Future.wait(toCancel.map((s) => s.cancel()));
};
- }
+ };
return controller.stream;
}
}
diff --git a/pkgs/stream_transform/test/switch_test.dart b/pkgs/stream_transform/test/switch_test.dart
index fbae7d7..91f10c8 100644
--- a/pkgs/stream_transform/test/switch_test.dart
+++ b/pkgs/stream_transform/test/switch_test.dart
@@ -82,12 +82,9 @@
await new Future(() {});
await outer.close();
-
expect(isDone, false);
await second.close();
-
- await new Future(() {});
expect(isDone, true);
});
@@ -97,11 +94,9 @@
outer.add(first.stream);
await new Future(() {});
await first.close();
- await new Future(() {});
expect(isDone, false);
await outer.close();
- await new Future(() {});
expect(isDone, true);
});