LCOV - code coverage report
Current view: top level - async-1.13.3/lib/src - stream_sink_completer.dart (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 0 38 0.0 %
Date: 2017-10-10 20:17:03 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 = new _CompleterSink<T>();
      28             : 
      29             :   /// Returns [sink] typed as a [_CompleterSink].
      30           0 :   _CompleterSink<T> get _sink => sink;
      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             :   static StreamSink<T> fromFuture<T>(Future<StreamSink<T>> sinkFuture) {
      40           0 :     var completer = new 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             :   void setDestinationSink(StreamSink<T> destinationSink) {
      61           0 :     if (_sink._destinationSink != null) {
      62           0 :       throw new 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             :   void setError(error, [StackTrace stackTrace]) {
      74           0 :     setDestinationSink(new 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             :   Future get done {
     102           0 :     if (_doneCompleter != null) return _doneCompleter.future;
     103           0 :     if (_destinationSink == null) {
     104           0 :       _doneCompleter = new Completer.sync();
     105           0 :       return _doneCompleter.future;
     106             :     }
     107           0 :     return _destinationSink.done;
     108             :   }
     109             : 
     110             :   void add(T event) {
     111           0 :     if (_canSendDirectly) {
     112           0 :       _destinationSink.add(event);
     113             :     } else {
     114           0 :       _ensureController();
     115           0 :       _controller.add(event);
     116             :     }
     117             :   }
     118             : 
     119             :   void addError(error, [StackTrace stackTrace]) {
     120           0 :     if (_canSendDirectly) {
     121           0 :       _destinationSink.addError(error, stackTrace);
     122             :     } else {
     123           0 :       _ensureController();
     124           0 :       _controller.addError(error, stackTrace);
     125             :     }
     126             :   }
     127             : 
     128             :   Future addStream(Stream<T> stream) {
     129           0 :     if (_canSendDirectly) return _destinationSink.addStream(stream);
     130             : 
     131           0 :     _ensureController();
     132           0 :     return _controller.addStream(stream, cancelOnError: false);
     133             :   }
     134             : 
     135             :   Future close() {
     136           0 :     if (_canSendDirectly) {
     137           0 :       _destinationSink.close();
     138             :     } else {
     139           0 :       _ensureController();
     140           0 :       _controller.close();
     141             :     }
     142           0 :     return done;
     143             :   }
     144             : 
     145             :   /// Create [_controller] if it doesn't yet exist.
     146             :   void _ensureController() {
     147           0 :     if (_controller == null) _controller = new StreamController(sync: true);
     148             :   }
     149             : 
     150             :   /// Sets the destination sink to which events from this sink will be provided.
     151             :   ///
     152             :   /// If set before the user adds events, events will be added directly to the
     153             :   /// destination sink. If the user adds events earlier, an intermediate sink is
     154             :   /// created using a stream controller, and the destination sink is linked to
     155             :   /// it later.
     156             :   void _setDestinationSink(StreamSink<T> sink) {
     157             :     assert(_destinationSink == null);
     158           0 :     _destinationSink = sink;
     159             : 
     160             :     // If the user has already added data, it's buffered in the controller, so
     161             :     // we add it to the sink.
     162           0 :     if (_controller != null) {
     163             :       // Catch any error that may come from [addStream] or [sink.close]. They'll
     164             :       // be reported through [done] anyway.
     165             :       sink
     166           0 :           .addStream(_controller.stream)
     167           0 :           .whenComplete(sink.close)
     168           0 :           .catchError((_) {});
     169             :     }
     170             : 
     171             :     // If the user has already asked when the sink is done, connect the sink's
     172             :     // done callback to that completer.
     173           0 :     if (_doneCompleter != null) {
     174           0 :       _doneCompleter.complete(sink.done);
     175             :     }
     176             :   }
     177             : }

Generated by: LCOV version 1.13