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

          Line data    Source code
       1             : // Copyright (c) 2016, 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 'null_stream_sink.dart';
       8             : 
       9             : /// A [sink] where the destination is provided later.
      10             : ///
      11             : /// The [sink] is a normal sink that you can add events to to immediately, but
      12             : /// until [setDestinationSink] is called, the events will be buffered.
      13             : ///
      14             : /// The same effect can be achieved by using a [StreamController] and adding it
      15             : /// to the sink using [Sink.addStream] when the destination sink is ready. This
      16             : /// class attempts to shortcut some of the overhead when possible. For example,
      17             : /// if the [sink] only has events added after the destination sink has been set,
      18             : /// those events are added directly to the sink.
      19             : class StreamSinkCompleter<T> {
      20             :   /// The sink for this completer.
      21             :   ///
      22             :   /// When a destination sink is provided, events that have been passed to the
      23             :   /// sink will be forwarded to the destination.
      24             :   ///
      25             :   /// Events can be added to the sink either before or after a destination sink
      26             :   /// is set.
      27             :   final StreamSink<T> sink = _CompleterSink<T>();
      28             : 
      29             :   /// Returns [sink] typed as a [_CompleterSink].
      30           0 :   _CompleterSink<T> get _sink => sink as _CompleterSink<T>;
      31             : 
      32             :   /// Convert a `Future<StreamSink>` to a `StreamSink`.
      33             :   ///
      34             :   /// This creates a sink using a sink completer, and sets the destination sink
      35             :   /// to the result of the future when the future completes.
      36             :   ///
      37             :   /// If the future completes with an error, the returned sink will instead
      38             :   /// be closed. Its [Sink.done] future will contain the error.
      39           0 :   static StreamSink<T> fromFuture<T>(Future<StreamSink<T>> sinkFuture) {
      40           0 :     var completer = StreamSinkCompleter<T>();
      41           0 :     sinkFuture.then(completer.setDestinationSink, onError: completer.setError);
      42           0 :     return completer.sink;
      43             :   }
      44             : 
      45             :   /// Sets a sink as the destination for events from the [StreamSinkCompleter]'s
      46             :   /// [sink].
      47             :   ///
      48             :   /// The completer's [sink] will act exactly as [destinationSink].
      49             :   ///
      50             :   /// If the destination sink is set before events are added to [sink], further
      51             :   /// events are forwarded directly to [destinationSink].
      52             :   ///
      53             :   /// If events are added to [sink] before setting the destination sink, they're
      54             :   /// buffered until the destination is available.
      55             :   ///
      56             :   /// A destination sink may be set at most once.
      57             :   ///
      58             :   /// Either of [setDestinationSink] or [setError] may be called at most once.
      59             :   /// Trying to call either of them again will fail.
      60           0 :   void setDestinationSink(StreamSink<T> destinationSink) {
      61           0 :     if (_sink._destinationSink != null) {
      62           0 :       throw StateError('Destination sink already set');
      63             :     }
      64           0 :     _sink._setDestinationSink(destinationSink);
      65             :   }
      66             : 
      67             :   /// Completes this to a closed sink whose [Sink.done] future emits [error].
      68             :   ///
      69             :   /// This is useful when the process of loading the sink fails.
      70             :   ///
      71             :   /// Either of [setDestinationSink] or [setError] may be called at most once.
      72             :   /// Trying to call either of them again will fail.
      73           0 :   void setError(Object error, [StackTrace? stackTrace]) {
      74           0 :     setDestinationSink(NullStreamSink.error(error, stackTrace));
      75             :   }
      76             : }
      77             : 
      78             : /// [StreamSink] completed by [StreamSinkCompleter].
      79             : class _CompleterSink<T> implements StreamSink<T> {
      80             :   /// Controller for an intermediate sink.
      81             :   ///
      82             :   /// Created if the user adds events to this sink before the destination sink
      83             :   /// is set.
      84             :   StreamController<T>? _controller;
      85             : 
      86             :   /// Completer for [done].
      87             :   ///
      88             :   /// Created if the user requests the [done] future before the destination sink
      89             :   /// is set.
      90             :   Completer? _doneCompleter;
      91             : 
      92             :   /// Destination sink for the events added to this sink.
      93             :   ///
      94             :   /// Set when [StreamSinkCompleter.setDestinationSink] is called.
      95             :   StreamSink<T>? _destinationSink;
      96             : 
      97             :   /// Whether events should be sent directly to [_destinationSink], as opposed
      98             :   /// to going through [_controller].
      99           0 :   bool get _canSendDirectly => _controller == null && _destinationSink != null;
     100             : 
     101           0 :   @override
     102             :   Future get done {
     103           0 :     if (_doneCompleter != null) return _doneCompleter!.future;
     104           0 :     if (_destinationSink == null) {
     105           0 :       _doneCompleter = Completer.sync();
     106           0 :       return _doneCompleter!.future;
     107             :     }
     108           0 :     return _destinationSink!.done;
     109             :   }
     110             : 
     111           0 :   @override
     112             :   void add(T event) {
     113           0 :     if (_canSendDirectly) {
     114           0 :       _destinationSink!.add(event);
     115             :     } else {
     116           0 :       _ensureController().add(event);
     117             :     }
     118             :   }
     119             : 
     120           0 :   @override
     121             :   void addError(error, [StackTrace? stackTrace]) {
     122           0 :     if (_canSendDirectly) {
     123           0 :       _destinationSink!.addError(error, stackTrace);
     124             :     } else {
     125           0 :       _ensureController().addError(error, stackTrace);
     126             :     }
     127             :   }
     128             : 
     129           0 :   @override
     130             :   Future addStream(Stream<T> stream) {
     131           0 :     if (_canSendDirectly) return _destinationSink!.addStream(stream);
     132             : 
     133           0 :     return _ensureController().addStream(stream, cancelOnError: false);
     134             :   }
     135             : 
     136           0 :   @override
     137             :   Future close() {
     138           0 :     if (_canSendDirectly) {
     139           0 :       _destinationSink!.close();
     140             :     } else {
     141           0 :       _ensureController().close();
     142             :     }
     143           0 :     return done;
     144             :   }
     145             : 
     146             :   /// Create [_controller] if it doesn't yet exist.
     147           0 :   StreamController<T> _ensureController() {
     148           0 :     return _controller ??= StreamController(sync: true);
     149             :   }
     150             : 
     151             :   /// Sets the destination sink to which events from this sink will be provided.
     152             :   ///
     153             :   /// If set before the user adds events, events will be added directly to the
     154             :   /// destination sink. If the user adds events earlier, an intermediate sink is
     155             :   /// created using a stream controller, and the destination sink is linked to
     156             :   /// it later.
     157           0 :   void _setDestinationSink(StreamSink<T> sink) {
     158           0 :     assert(_destinationSink == null);
     159           0 :     _destinationSink = sink;
     160             : 
     161             :     // If the user has already added data, it's buffered in the controller, so
     162             :     // we add it to the sink.
     163           0 :     if (_controller != null) {
     164             :       // Catch any error that may come from [addStream] or [sink.close]. They'll
     165             :       // be reported through [done] anyway.
     166             :       sink
     167           0 :           .addStream(_controller!.stream)
     168           0 :           .whenComplete(sink.close)
     169           0 :           .catchError((_) {});
     170             :     }
     171             : 
     172             :     // If the user has already asked when the sink is done, connect the sink's
     173             :     // done callback to that completer.
     174           0 :     if (_doneCompleter != null) {
     175           0 :       _doneCompleter!.complete(sink.done);
     176             :     }
     177             :   }
     178             : }

Generated by: LCOV version 1.14