LCOV - code coverage report
Current view: top level - async-2.5.0/lib/src - stream_completer.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 14 41 34.1 %
Date: 2021-11-28 14:37:50 Functions: 0 0 -

          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             : /// A single-subscription [stream] where the contents are provided later.
       8             : ///
       9             : /// It is generally recommended that you never create a `Future<Stream>`
      10             : /// because you can just directly create a stream that doesn't do anything
      11             : /// until it's ready to do so.
      12             : /// This class can be used to create such a stream.
      13             : ///
      14             : /// The [stream] is a normal stream that you can listen to immediately,
      15             : /// but until either [setSourceStream] or [setEmpty] is called,
      16             : /// the stream won't produce any events.
      17             : ///
      18             : /// The same effect can be achieved by using a [StreamController]
      19             : /// and adding the stream using `addStream` when both
      20             : /// the controller's stream is listened to and the source stream is ready.
      21             : /// This class attempts to shortcut some of the overhead when possible.
      22             : /// For example, if the [stream] is only listened to
      23             : /// after the source stream has been set,
      24             : /// the listen is performed directly on the source stream.
      25             : class StreamCompleter<T> {
      26             :   /// The stream doing the actual work, is returned by [stream].
      27             :   final _stream = _CompleterStream<T>();
      28             : 
      29             :   /// Convert a `Future<Stream>` to a `Stream`.
      30             :   ///
      31             :   /// This creates a stream using a stream completer,
      32             :   /// and sets the source stream to the result of the future when the
      33             :   /// future completes.
      34             :   ///
      35             :   /// If the future completes with an error, the returned stream will
      36             :   /// instead contain just that error.
      37           0 :   static Stream<T> fromFuture<T>(Future<Stream<T>> streamFuture) {
      38           0 :     var completer = StreamCompleter<T>();
      39           0 :     streamFuture.then(completer.setSourceStream, onError: completer.setError);
      40           0 :     return completer.stream;
      41             :   }
      42             : 
      43             :   /// The stream of this completer.
      44             :   ///
      45             :   /// This stream is always a single-subscription stream.
      46             :   ///
      47             :   /// When a source stream is provided, its events will be forwarded to
      48             :   /// listeners on this stream.
      49             :   ///
      50             :   /// The stream can be listened either before or after a source stream
      51             :   /// is set.
      52          22 :   Stream<T> get stream => _stream;
      53             : 
      54             :   /// Set a stream as the source of events for the [StreamCompleter]'s
      55             :   /// [stream].
      56             :   ///
      57             :   /// The completer's `stream` will act exactly as [sourceStream].
      58             :   ///
      59             :   /// If the source stream is set before [stream] is listened to,
      60             :   /// the listen call on [stream] is forwarded directly to [sourceStream].
      61             :   ///
      62             :   /// If [stream] is listened to before setting the source stream,
      63             :   /// an intermediate subscription is created. It looks like a completely
      64             :   /// normal subscription, and can be paused or canceled, but it won't
      65             :   /// produce any events until a source stream is provided.
      66             :   ///
      67             :   /// If the `stream` subscription is canceled before a source stream is set,
      68             :   /// the source stream will be listened to and immediately canceled again.
      69             :   ///
      70             :   /// Otherwise, when the source stream is then set,
      71             :   /// it is immediately listened to, and its events are forwarded to the
      72             :   /// existing subscription.
      73             :   ///
      74             :   /// Any one of [setSourceStream], [setEmpty], and [setError] may be called at
      75             :   /// most once. Trying to call any of them again will fail.
      76          11 :   void setSourceStream(Stream<T> sourceStream) {
      77          22 :     if (_stream._isSourceStreamSet) {
      78           0 :       throw StateError('Source stream already set');
      79             :     }
      80          22 :     _stream._setSourceStream(sourceStream);
      81             :   }
      82             : 
      83             :   /// Equivalent to setting an empty stream using [setSourceStream].
      84             :   ///
      85             :   /// Any one of [setSourceStream], [setEmpty], and [setError] may be called at
      86             :   /// most once. Trying to call any of them again will fail.
      87           0 :   void setEmpty() {
      88           0 :     if (_stream._isSourceStreamSet) {
      89           0 :       throw StateError('Source stream already set');
      90             :     }
      91           0 :     _stream._setEmpty();
      92             :   }
      93             : 
      94             :   /// Completes this to a stream that emits [error] and then closes.
      95             :   ///
      96             :   /// This is useful when the process of creating the data for the stream fails.
      97             :   ///
      98             :   /// Any one of [setSourceStream], [setEmpty], and [setError] may be called at
      99             :   /// most once. Trying to call any of them again will fail.
     100           0 :   void setError(Object error, [StackTrace? stackTrace]) {
     101           0 :     setSourceStream(Stream.fromFuture(Future.error(error, stackTrace)));
     102             :   }
     103             : }
     104             : 
     105             : /// Stream completed by [StreamCompleter].
     106             : class _CompleterStream<T> extends Stream<T> {
     107             :   /// Controller for an intermediate stream.
     108             :   ///
     109             :   /// Created if the user listens on this stream before the source stream
     110             :   /// is set, or if using [_setEmpty] so there is no source stream.
     111             :   StreamController<T>? _controller;
     112             : 
     113             :   /// Source stream for the events provided by this stream.
     114             :   ///
     115             :   /// Set when the completer sets the source stream using [_setSourceStream]
     116             :   /// or [_setEmpty].
     117             :   Stream<T>? _sourceStream;
     118             : 
     119          11 :   @override
     120             :   StreamSubscription<T> listen(void Function(T)? onData,
     121             :       {Function? onError, void Function()? onDone, bool? cancelOnError}) {
     122          11 :     if (_controller == null) {
     123          11 :       var sourceStream = _sourceStream;
     124          11 :       if (sourceStream != null && !sourceStream.isBroadcast) {
     125             :         // If the source stream is itself single subscription,
     126             :         // just listen to it directly instead of creating a controller.
     127          11 :         return sourceStream.listen(onData,
     128             :             onError: onError, onDone: onDone, cancelOnError: cancelOnError);
     129             :       }
     130           0 :       _ensureController();
     131           0 :       if (_sourceStream != null) {
     132           0 :         _linkStreamToController();
     133             :       }
     134             :     }
     135           0 :     return _controller!.stream.listen(onData,
     136             :         onError: onError, onDone: onDone, cancelOnError: cancelOnError);
     137             :   }
     138             : 
     139             :   /// Whether a source stream has been set.
     140             :   ///
     141             :   /// Used to throw an error if trying to set a source stream twice.
     142          22 :   bool get _isSourceStreamSet => _sourceStream != null;
     143             : 
     144             :   /// Sets the source stream providing the events for this stream.
     145             :   ///
     146             :   /// If set before the user listens, listen calls will be directed directly
     147             :   /// to the source stream. If the user listenes earlier, and intermediate
     148             :   /// stream is created using a stream controller, and the source stream is
     149             :   /// linked into that stream later.
     150          11 :   void _setSourceStream(Stream<T> sourceStream) {
     151          11 :     assert(_sourceStream == null);
     152          11 :     _sourceStream = sourceStream;
     153          11 :     if (_controller != null) {
     154             :       // User has already listened, so provide the data through controller.
     155           0 :       _linkStreamToController();
     156             :     }
     157             :   }
     158             : 
     159             :   /// Links source stream to controller when both are available.
     160           0 :   void _linkStreamToController() {
     161           0 :     var controller = _controller!;
     162             :     controller
     163           0 :         .addStream(_sourceStream!, cancelOnError: false)
     164           0 :         .whenComplete(controller.close);
     165             :   }
     166             : 
     167             :   /// Sets an empty source stream.
     168             :   ///
     169             :   /// Uses [_controller] for the stream, then closes the controller
     170             :   /// immediately.
     171           0 :   void _setEmpty() {
     172           0 :     assert(_sourceStream == null);
     173           0 :     var controller = _ensureController();
     174           0 :     _sourceStream = controller.stream; // Mark stream as set.
     175           0 :     controller.close();
     176             :   }
     177             : 
     178             :   // Creates the [_controller].
     179           0 :   StreamController<T> _ensureController() {
     180           0 :     return _controller ??= StreamController<T>(sync: true);
     181             :   }
     182             : }

Generated by: LCOV version 1.14