Line data Source code
1 : // Copyright (c) 2015, 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 : import 'dart:async';
6 :
7 : import "delegate/stream_subscription.dart";
8 :
9 : /// A [Stream] adapter for a [StreamSubscription].
10 : ///
11 : /// This class allows a `StreamSubscription` to be treated as a `Stream`.
12 : ///
13 : /// The subscription is paused until the stream is listened to,
14 : /// then it is resumed and the events are passed on to the
15 : /// stream's new subscription.
16 : ///
17 : /// This class assumes that is has control over the original subscription.
18 : /// If other code is accessing the subscription, results may be unpredictable.
19 : class SubscriptionStream<T> extends Stream<T> {
20 : /// The subscription providing the events for this stream.
21 : StreamSubscription<T> _source;
22 :
23 : /// Create a single-subscription `Stream` from [subscription].
24 : ///
25 : /// The `subscription` should not be paused. This class will not resume prior
26 : /// pauses, so being paused is indistinguishable from not providing any
27 : /// events.
28 : ///
29 : /// If the `subscription` doesn't send any `done` events, neither will this
30 : /// stream. That may be an issue if `subscription` was made to cancel on
31 : /// an error.
32 : SubscriptionStream(StreamSubscription<T> subscription)
33 0 : : _source = subscription {
34 0 : _source.pause();
35 : // Clear callbacks to avoid keeping them alive unnecessarily.
36 0 : _source.onData(null);
37 0 : _source.onError(null);
38 0 : _source.onDone(null);
39 : }
40 :
41 : StreamSubscription<T> listen(void onData(T event),
42 : {Function onError, void onDone(), bool cancelOnError}) {
43 0 : if (_source == null) {
44 0 : throw new StateError("Stream has already been listened to.");
45 : }
46 0 : cancelOnError = (true == cancelOnError);
47 0 : var subscription = _source;
48 0 : _source = null;
49 :
50 : var result = cancelOnError
51 0 : ? new _CancelOnErrorSubscriptionWrapper<T>(subscription)
52 : : subscription;
53 0 : result.onData(onData);
54 0 : result.onError(onError);
55 0 : result.onDone(onDone);
56 0 : subscription.resume();
57 : return result;
58 : }
59 : }
60 :
61 : /// Subscription wrapper that cancels on error.
62 : ///
63 : /// Used by [SubscriptionStream] when forwarding a subscription
64 : /// created with `cancelOnError` as `true` to one with (assumed)
65 : /// `cancelOnError` as `false`. It automatically cancels the
66 : /// source subscription on the first error.
67 : class _CancelOnErrorSubscriptionWrapper<T>
68 : extends DelegatingStreamSubscription<T> {
69 : _CancelOnErrorSubscriptionWrapper(StreamSubscription<T> subscription)
70 0 : : super(subscription);
71 :
72 : void onError(Function handleError) {
73 : // Cancel when receiving an error.
74 0 : super.onError((error, StackTrace stackTrace) {
75 0 : var cancelFuture = super.cancel();
76 : if (cancelFuture != null) {
77 : // Wait for the cancel to complete before sending the error event.
78 0 : cancelFuture.whenComplete(() {
79 0 : if (handleError is ZoneBinaryCallback) {
80 0 : handleError(error, stackTrace);
81 : } else {
82 0 : handleError(error);
83 : }
84 : });
85 : } else {
86 0 : if (handleError is ZoneBinaryCallback) {
87 0 : handleError(error, stackTrace);
88 : } else {
89 0 : handleError(error);
90 : }
91 : }
92 : });
93 : }
94 : }
|