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 11 : SubscriptionStream(StreamSubscription<T> subscription) 33 : : _source = subscription { 34 11 : var source = _source!; 35 11 : source.pause(); 36 : // Clear callbacks to avoid keeping them alive unnecessarily. 37 11 : source.onData(null); 38 11 : source.onError(null); 39 11 : source.onDone(null); 40 : } 41 : 42 11 : @override 43 : StreamSubscription<T> listen(void Function(T)? onData, 44 : {Function? onError, void Function()? onDone, bool? cancelOnError}) { 45 11 : var subscription = _source; 46 : if (subscription == null) { 47 0 : throw StateError('Stream has already been listened to.'); 48 : } 49 11 : cancelOnError = (true == cancelOnError); 50 11 : _source = null; 51 : 52 : var result = cancelOnError 53 0 : ? _CancelOnErrorSubscriptionWrapper<T>(subscription) 54 : : subscription; 55 11 : result.onData(onData); 56 11 : result.onError(onError); 57 11 : result.onDone(onDone); 58 11 : subscription.resume(); 59 : return result; 60 : } 61 : } 62 : 63 : /// Subscription wrapper that cancels on error. 64 : /// 65 : /// Used by [SubscriptionStream] when forwarding a subscription 66 : /// created with `cancelOnError` as `true` to one with (assumed) 67 : /// `cancelOnError` as `false`. It automatically cancels the 68 : /// source subscription on the first error. 69 : class _CancelOnErrorSubscriptionWrapper<T> 70 : extends DelegatingStreamSubscription<T> { 71 0 : _CancelOnErrorSubscriptionWrapper(StreamSubscription<T> subscription) 72 0 : : super(subscription); 73 : 74 0 : @override 75 : void onError(Function? handleError) { 76 : // Cancel when receiving an error. 77 0 : super.onError((error, StackTrace stackTrace) { 78 : // Wait for the cancel to complete before sending the error event. 79 0 : super.cancel().whenComplete(() { 80 0 : if (handleError is ZoneBinaryCallback) { 81 : handleError(error, stackTrace); 82 : } else if (handleError != null) { 83 0 : handleError(error); 84 : } 85 : }); 86 : }); 87 : } 88 : }