LCOV - code coverage report
Current view: top level - async-1.13.3/lib/src - stream_queue.dart (source / functions) Hit Total Coverage
Test: coverage.lcov Lines: 0 195 0.0 %
Date: 2017-10-10 20:17:03 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             : import 'dart:collection';
       7             : 
       8             : import 'package:collection/collection.dart';
       9             : 
      10             : import "cancelable_operation.dart";
      11             : import "result.dart";
      12             : import "subscription_stream.dart";
      13             : import "stream_completer.dart";
      14             : import "stream_splitter.dart";
      15             : 
      16             : /// An asynchronous pull-based interface for accessing stream events.
      17             : ///
      18             : /// Wraps a stream and makes individual events available on request.
      19             : ///
      20             : /// You can request (and reserve) one or more events from the stream,
      21             : /// and after all previous requests have been fulfilled, stream events
      22             : /// go towards fulfilling your request.
      23             : ///
      24             : /// For example, if you ask for [next] two times, the returned futures
      25             : /// will be completed by the next two unrequested events from the stream.
      26             : ///
      27             : /// The stream subscription is paused when there are no active
      28             : /// requests.
      29             : ///
      30             : /// Some streams, including broadcast streams, will buffer
      31             : /// events while paused, so waiting too long between requests may
      32             : /// cause memory bloat somewhere else.
      33             : ///
      34             : /// This is similar to, but more convenient than, a [StreamIterator].
      35             : /// A `StreamIterator` requires you to manually check when a new event is
      36             : /// available and you can only access the value of that event until you
      37             : /// check for the next one. A `StreamQueue` allows you to request, for example,
      38             : /// three events at a time, either individually, as a group using [take]
      39             : /// or [skip], or in any combination.
      40             : ///
      41             : /// You can also ask to have the [rest] of the stream provided as
      42             : /// a new stream. This allows, for example, taking the first event
      43             : /// out of a stream and continuing to use the rest of the stream as a stream.
      44             : ///
      45             : /// Example:
      46             : ///
      47             : ///     var events = new StreamQueue<String>(someStreamOfLines);
      48             : ///     var first = await events.next;
      49             : ///     while (first.startsWith('#')) {
      50             : ///       // Skip comments.
      51             : ///       first = await events.next;
      52             : ///     }
      53             : ///
      54             : ///     if (first.startsWith(MAGIC_MARKER)) {
      55             : ///       var headerCount =
      56             : ///           first.parseInt(first.substring(MAGIC_MARKER.length + 1));
      57             : ///       handleMessage(headers: await events.take(headerCount),
      58             : ///                     body: events.rest);
      59             : ///       return;
      60             : ///     }
      61             : ///     // Error handling.
      62             : ///
      63             : /// When you need no further events the `StreamQueue` should be closed
      64             : /// using [cancel]. This releases the underlying stream subscription.
      65             : abstract class StreamQueue<T> {
      66             :   // This class maintains two queues: one of events and one of requests.
      67             :   // The active request (the one in front of the queue) is called with
      68             :   // the current event queue when it becomes active, every time a
      69             :   // new event arrives, and when the event source closes.
      70             :   //
      71             :   // If the request returns `true`, it's complete and will be removed from the
      72             :   // request queue.
      73             :   // If the request returns `false`, it needs more events, and will be called
      74             :   // again when new events are available. It may trigger a call itself by
      75             :   // calling [_updateRequests].
      76             :   // The request can remove events that it uses, or keep them in the event
      77             :   // queue until it has all that it needs.
      78             :   //
      79             :   // This model is very flexible and easily extensible.
      80             :   // It allows requests that don't consume events (like [hasNext]) or
      81             :   // potentially a request that takes either five or zero events, determined
      82             :   // by the content of the fifth event.
      83             : 
      84             :   /// Whether the event source is done.
      85             :   bool _isDone = false;
      86             : 
      87             :   /// Whether a closing operation has been performed on the stream queue.
      88             :   ///
      89             :   /// Closing operations are [cancel] and [rest].
      90             :   bool _isClosed = false;
      91             : 
      92             :   /// The number of events dispatched by this queue.
      93             :   ///
      94             :   /// This counts error events. It doesn't count done events, or events
      95             :   /// dispatched to a stream returned by [rest].
      96           0 :   int get eventsDispatched => _eventsReceived - _eventQueue.length;
      97             : 
      98             :   /// The number of events received by this queue.
      99             :   var _eventsReceived = 0;
     100             : 
     101             :   /// Queue of events not used by a request yet.
     102             :   final QueueList<Result> _eventQueue = new QueueList();
     103             : 
     104             :   /// Queue of pending requests.
     105             :   ///
     106             :   /// Access through methods below to ensure consistency.
     107             :   final Queue<_EventRequest> _requestQueue = new Queue();
     108             : 
     109             :   /// Create a `StreamQueue` of the events of [source].
     110             :   factory StreamQueue(Stream<T> source) = _StreamQueue<T>;
     111             : 
     112           0 :   StreamQueue._();
     113             : 
     114             :   /// Asks if the stream has any more events.
     115             :   ///
     116             :   /// Returns a future that completes with `true` if the stream has any
     117             :   /// more events, whether data or error.
     118             :   /// If the stream closes without producing any more events, the returned
     119             :   /// future completes with `false`.
     120             :   ///
     121             :   /// Can be used before using [next] to avoid getting an error in the
     122             :   /// future returned by `next` in the case where there are no more events.
     123             :   /// Another alternative is to use `take(1)` which returns either zero or
     124             :   /// one events.
     125             :   Future<bool> get hasNext {
     126           0 :     if (!_isClosed) {
     127           0 :       var hasNextRequest = new _HasNextRequest();
     128           0 :       _addRequest(hasNextRequest);
     129           0 :       return hasNextRequest.future;
     130             :     }
     131           0 :     throw _failClosed();
     132             :   }
     133             : 
     134             :   /// Look at the next [count] data events without consuming them.
     135             :   ///
     136             :   /// Works like [take] except that the events are left in the queue.
     137             :   /// If one of the next [count] events is an error, the returned future
     138             :   /// completes with this error, and the error is still left in the queue.
     139             :   Future<List<T>> lookAhead(int count) {
     140           0 :     if (count < 0) throw new RangeError.range(count, 0, null, "count");
     141           0 :     if (!_isClosed) {
     142           0 :       var request = new _LookAheadRequest<T>(count);
     143           0 :       _addRequest(request);
     144           0 :       return request.future;
     145             :     }
     146           0 :     throw _failClosed();
     147             :   }
     148             : 
     149             :   /// Requests the next (yet unrequested) event from the stream.
     150             :   ///
     151             :   /// When the requested event arrives, the returned future is completed with
     152             :   /// the event.
     153             :   /// If the event is a data event, the returned future completes
     154             :   /// with its value.
     155             :   /// If the event is an error event, the returned future completes with
     156             :   /// its error and stack trace.
     157             :   /// If the stream closes before an event arrives, the returned future
     158             :   /// completes with a [StateError].
     159             :   ///
     160             :   /// It's possible to have several pending [next] calls (or other requests),
     161             :   /// and they will be completed in the order they were requested, by the
     162             :   /// first events that were not consumed by previous requeusts.
     163             :   Future<T> get next {
     164           0 :     if (!_isClosed) {
     165           0 :       var nextRequest = new _NextRequest<T>();
     166           0 :       _addRequest(nextRequest);
     167           0 :       return nextRequest.future;
     168             :     }
     169           0 :     throw _failClosed();
     170             :   }
     171             : 
     172             :   /// Looks at the next (yet unrequested) event from the stream.
     173             :   ///
     174             :   /// Like [next] except that the event is not consumed.
     175             :   /// If the next event is an error event, it stays in the queue.
     176             :   Future<T> get peek {
     177           0 :     if (!_isClosed) {
     178           0 :       var nextRequest = new _PeekRequest<T>();
     179           0 :       _addRequest(nextRequest);
     180           0 :       return nextRequest.future;
     181             :     }
     182           0 :     throw _failClosed();
     183             :   }
     184             : 
     185             :   /// Returns a stream of all the remaning events of the source stream.
     186             :   ///
     187             :   /// All requested [next], [skip] or [take] operations are completed
     188             :   /// first, and then any remaining events are provided as events of
     189             :   /// the returned stream.
     190             :   ///
     191             :   /// Using `rest` closes this stream queue. After getting the
     192             :   /// `rest` the caller may no longer request other events, like
     193             :   /// after calling [cancel].
     194             :   Stream<T> get rest {
     195           0 :     if (_isClosed) {
     196           0 :       throw _failClosed();
     197             :     }
     198           0 :     var request = new _RestRequest<T>(this);
     199           0 :     _isClosed = true;
     200           0 :     _addRequest(request);
     201           0 :     return request.stream;
     202             :   }
     203             : 
     204             :   /// Skips the next [count] *data* events.
     205             :   ///
     206             :   /// The [count] must be non-negative.
     207             :   ///
     208             :   /// When successful, this is equivalent to using [take]
     209             :   /// and ignoring the result.
     210             :   ///
     211             :   /// If an error occurs before `count` data events have been skipped,
     212             :   /// the returned future completes with that error instead.
     213             :   ///
     214             :   /// If the stream closes before `count` data events,
     215             :   /// the remaining unskipped event count is returned.
     216             :   /// If the returned future completes with the integer `0`,
     217             :   /// then all events were succssfully skipped. If the value
     218             :   /// is greater than zero then the stream ended early.
     219             :   Future<int> skip(int count) {
     220           0 :     if (count < 0) throw new RangeError.range(count, 0, null, "count");
     221           0 :     if (!_isClosed) {
     222           0 :       var request = new _SkipRequest(count);
     223           0 :       _addRequest(request);
     224           0 :       return request.future;
     225             :     }
     226           0 :     throw _failClosed();
     227             :   }
     228             : 
     229             :   /// Requests the next [count] data events as a list.
     230             :   ///
     231             :   /// The [count] must be non-negative.
     232             :   ///
     233             :   /// Equivalent to calling [next] `count` times and
     234             :   /// storing the data values in a list.
     235             :   ///
     236             :   /// If an error occurs before `count` data events has
     237             :   /// been collected, the returned future completes with
     238             :   /// that error instead.
     239             :   ///
     240             :   /// If the stream closes before `count` data events,
     241             :   /// the returned future completes with the list
     242             :   /// of data collected so far. That is, the returned
     243             :   /// list may have fewer than [count] elements.
     244             :   Future<List<T>> take(int count) {
     245           0 :     if (count < 0) throw new RangeError.range(count, 0, null, "count");
     246           0 :     if (!_isClosed) {
     247           0 :       var request = new _TakeRequest<T>(count);
     248           0 :       _addRequest(request);
     249           0 :       return request.future;
     250             :     }
     251           0 :     throw _failClosed();
     252             :   }
     253             : 
     254             :   /// Requests a transaction that can conditionally consume events.
     255             :   ///
     256             :   /// The transaction can create copies of this queue at the current position
     257             :   /// using [StreamQueueTransaction.newQueue]. Each of these queues is
     258             :   /// independent of one another and of the parent queue. The transaction
     259             :   /// finishes when one of two methods is called:
     260             :   ///
     261             :   /// * [StreamQueueTransaction.commit] updates the parent queue's position to
     262             :   ///   match that of one of the copies.
     263             :   ///
     264             :   /// * [StreamQueueTransaction.reject] causes the parent queue to continue as
     265             :   ///   though [startTransaction] hadn't been called.
     266             :   ///
     267             :   /// Until the transaction finishes, this queue won't emit any events.
     268             :   ///
     269             :   /// See also [withTransaction] and [cancelable].
     270             :   ///
     271             :   /// ```dart
     272             :   /// /// Consumes all empty lines from the beginning of [lines].
     273             :   /// Future consumeEmptyLines(StreamQueue<String> lines) async {
     274             :   ///   while (await lines.hasNext) {
     275             :   ///     var transaction = lines.startTransaction();
     276             :   ///     var queue = transaction.newQueue();
     277             :   ///     if ((await queue.next).isNotEmpty) {
     278             :   ///       transaction.reject();
     279             :   ///       return;
     280             :   ///     } else {
     281             :   ///       transaction.commit(queue);
     282             :   ///     }
     283             :   ///   }
     284             :   /// }
     285             :   /// ```
     286             :   StreamQueueTransaction<T> startTransaction() {
     287           0 :     if (_isClosed) throw _failClosed();
     288             : 
     289           0 :     var request = new _TransactionRequest(this);
     290           0 :     _addRequest(request);
     291           0 :     return request.transaction;
     292             :   }
     293             : 
     294             :   /// Passes a copy of this queue to [callback], and updates this queue to match
     295             :   /// the copy's position if [callback] returns `true`.
     296             :   ///
     297             :   /// This queue won't emit any events until [callback] returns. If it returns
     298             :   /// `false`, this queue continues as though [withTransaction] hadn't been
     299             :   /// called. If it throws an error, this updates this queue to match the copy's
     300             :   /// position and throws the error from the returned `Future`.
     301             :   ///
     302             :   /// Returns the same value as [callback].
     303             :   ///
     304             :   /// See also [startTransaction] and [cancelable].
     305             :   ///
     306             :   /// ```dart
     307             :   /// /// Consumes all empty lines from the beginning of [lines].
     308             :   /// Future consumeEmptyLines(StreamQueue<String> lines) async {
     309             :   ///   while (await lines.hasNext) {
     310             :   ///     // Consume a line if it's empty, otherwise return.
     311             :   ///     if (!await lines.withTransaction(
     312             :   ///         (queue) async => (await queue.next).isEmpty)) {
     313             :   ///       return;
     314             :   ///     }
     315             :   ///   }
     316             :   /// }
     317             :   /// ```
     318             :   Future<bool> withTransaction(Future<bool> callback(StreamQueue<T> queue)) {
     319           0 :     var transaction = startTransaction();
     320             : 
     321             :     /// Avoid async/await to ensure that [startTransaction] is called
     322             :     /// synchronously and so ends up in the right place in the request queue.
     323           0 :     var queue = transaction.newQueue();
     324           0 :     return callback(queue).then((result) {
     325             :       if (result) {
     326           0 :         transaction.commit(queue);
     327             :       } else {
     328           0 :         transaction.reject();
     329             :       }
     330             :       return result;
     331             :     }, onError: (error) {
     332           0 :       transaction.commit(queue);
     333             :       throw error;
     334             :     });
     335             :   }
     336             : 
     337             :   /// Passes a copy of this queue to [callback], and updates this queue to match
     338             :   /// the copy's position once [callback] completes.
     339             :   ///
     340             :   /// If the returned [CancelableOperation] is canceled, this queue instead
     341             :   /// continues as though [cancelable] hadn't been called. Otherwise, it emits
     342             :   /// the same value or error as [callback].
     343             :   ///
     344             :   /// See also [startTransaction] and [withTransaction].
     345             :   ///
     346             :   /// ```dart
     347             :   /// final _stdinQueue = new StreamQueue(stdin);
     348             :   ///
     349             :   /// /// Returns an operation that completes when the user sends a line to
     350             :   /// /// standard input.
     351             :   /// ///
     352             :   /// /// If the operation is canceled, stops waiting for user input.
     353             :   /// CancelableOperation<String> nextStdinLine() =>
     354             :   ///     _stdinQueue.cancelable((queue) => queue.next);
     355             :   /// ```
     356             :   CancelableOperation<S> cancelable<S>(
     357             :       Future<S> callback(StreamQueue<T> queue)) {
     358           0 :     var transaction = startTransaction();
     359           0 :     var completer = new CancelableCompleter<S>(onCancel: () {
     360           0 :       transaction.reject();
     361             :     });
     362             : 
     363           0 :     var queue = transaction.newQueue();
     364           0 :     completer.complete(callback(queue).whenComplete(() {
     365           0 :       if (!completer.isCanceled) transaction.commit(queue);
     366             :     }));
     367             : 
     368           0 :     return completer.operation;
     369             :   }
     370             : 
     371             :   /// Cancels the underlying event source.
     372             :   ///
     373             :   /// If [immediate] is `false` (the default), the cancel operation waits until
     374             :   /// all previously requested events have been processed, then it cancels the
     375             :   /// subscription providing the events.
     376             :   ///
     377             :   /// If [immediate] is `true`, the source is instead canceled
     378             :   /// immediately. Any pending events are completed as though the underlying
     379             :   /// stream had closed.
     380             :   ///
     381             :   /// The returned future completes with the result of calling
     382             :   /// `cancel`.
     383             :   ///
     384             :   /// After calling `cancel`, no further events can be requested.
     385             :   /// None of [lookAhead], [next], [peek], [rest], [skip], [take] or [cancel]
     386             :   /// may be called again.
     387             :   Future cancel({bool immediate: false}) {
     388           0 :     if (_isClosed) throw _failClosed();
     389           0 :     _isClosed = true;
     390             : 
     391             :     if (!immediate) {
     392           0 :       var request = new _CancelRequest(this);
     393           0 :       _addRequest(request);
     394           0 :       return request.future;
     395             :     }
     396             : 
     397           0 :     if (_isDone && _eventQueue.isEmpty) return new Future.value();
     398           0 :     return _cancel();
     399             :   }
     400             : 
     401             :   // ------------------------------------------------------------------
     402             :   // Methods that may be called from the request implementations to
     403             :   // control the even stream.
     404             : 
     405             :   /// Matches events with requests.
     406             :   ///
     407             :   /// Called after receiving an event or when the event source closes.
     408             :   ///
     409             :   /// May be called by requests which have returned `false` (saying they
     410             :   /// are not yet done) so they can be checked again before any new
     411             :   /// events arrive.
     412             :   /// Any request returing `false` from `update` when `isDone` is `true`
     413             :   /// *must* call `_updateRequests` when they are ready to continue
     414             :   /// (since no further events will trigger the call).
     415             :   void _updateRequests() {
     416           0 :     while (_requestQueue.isNotEmpty) {
     417           0 :       if (_requestQueue.first.update(_eventQueue, _isDone)) {
     418           0 :         _requestQueue.removeFirst();
     419             :       } else {
     420             :         return;
     421             :       }
     422             :     }
     423             : 
     424           0 :     if (!_isDone) {
     425           0 :       _pause();
     426             :     }
     427             :   }
     428             : 
     429             :   /// Extracts a stream from the event source and makes this stream queue
     430             :   /// unusable.
     431             :   ///
     432             :   /// Can only be used by the very last request (the stream queue must
     433             :   /// be closed by that request).
     434             :   /// Only used by [rest].
     435             :   Stream<T> _extractStream();
     436             : 
     437             :   /// Requests that the event source pauses events.
     438             :   ///
     439             :   /// This is called automatically when the request queue is empty.
     440             :   ///
     441             :   /// The event source is restarted by the next call to [_ensureListening].
     442             :   void _pause();
     443             : 
     444             :   /// Ensures that we are listening on events from the event source.
     445             :   ///
     446             :   /// Starts listening for the first time or resumes after a [_pause].
     447             :   ///
     448             :   /// Is called automatically if a request requires more events.
     449             :   void _ensureListening();
     450             : 
     451             :   /// Cancels the underlying event source.
     452             :   Future _cancel();
     453             : 
     454             :   // ------------------------------------------------------------------
     455             :   // Methods called by the event source to add events or say that it's
     456             :   // done.
     457             : 
     458             :   /// Called when the event source adds a new data or error event.
     459             :   /// Always calls [_updateRequests] after adding.
     460             :   void _addResult(Result result) {
     461           0 :     _eventsReceived++;
     462           0 :     _eventQueue.add(result);
     463           0 :     _updateRequests();
     464             :   }
     465             : 
     466             :   /// Called when the event source is done.
     467             :   /// Always calls [_updateRequests] after adding.
     468             :   void _close() {
     469           0 :     _isDone = true;
     470           0 :     _updateRequests();
     471             :   }
     472             : 
     473             :   // ------------------------------------------------------------------
     474             :   // Internal helper methods.
     475             : 
     476             :   /// Returns an error for when a request is made after cancel.
     477             :   ///
     478             :   /// Returns a [StateError] with a message saying that either
     479             :   /// [cancel] or [rest] have already been called.
     480             :   Error _failClosed() {
     481           0 :     return new StateError("Already cancelled");
     482             :   }
     483             : 
     484             :   /// Adds a new request to the queue.
     485             :   ///
     486             :   /// If the request queue is empty and the request can be completed
     487             :   /// immediately, it skips the queue.
     488             :   void _addRequest(_EventRequest request) {
     489           0 :     if (_requestQueue.isEmpty) {
     490           0 :       if (request.update(_eventQueue, _isDone)) return;
     491           0 :       _ensureListening();
     492             :     }
     493           0 :     _requestQueue.add(request);
     494             :   }
     495             : }
     496             : 
     497             : /// The default implementation of [StreamQueue].
     498             : ///
     499             : /// This queue gets its events from a stream which is listened
     500             : /// to when a request needs events.
     501             : class _StreamQueue<T> extends StreamQueue<T> {
     502             :   /// Source of events.
     503             :   final Stream<T> _sourceStream;
     504             : 
     505             :   /// Subscription on [_sourceStream] while listening for events.
     506             :   ///
     507             :   /// Set to subscription when listening, and set to `null` when the
     508             :   /// subscription is done (and [_isDone] is set to true).
     509             :   StreamSubscription<T> _subscription;
     510             : 
     511           0 :   _StreamQueue(this._sourceStream) : super._();
     512             : 
     513             :   Future _cancel() {
     514           0 :     if (_isDone) return null;
     515           0 :     if (_subscription == null) _subscription = _sourceStream.listen(null);
     516           0 :     var future = _subscription.cancel();
     517           0 :     _close();
     518             :     return future;
     519             :   }
     520             : 
     521             :   void _ensureListening() {
     522           0 :     if (_isDone) return;
     523           0 :     if (_subscription == null) {
     524           0 :       _subscription = _sourceStream.listen((data) {
     525           0 :         _addResult(new Result.value(data));
     526             :       }, onError: (error, StackTrace stackTrace) {
     527           0 :         _addResult(new Result.error(error, stackTrace));
     528             :       }, onDone: () {
     529           0 :         _subscription = null;
     530           0 :         this._close();
     531             :       });
     532             :     } else {
     533           0 :       _subscription.resume();
     534             :     }
     535             :   }
     536             : 
     537             :   void _pause() {
     538           0 :     _subscription.pause();
     539             :   }
     540             : 
     541             :   Stream<T> _extractStream() {
     542             :     assert(_isClosed);
     543           0 :     if (_isDone) {
     544           0 :       return new Stream<T>.empty();
     545             :     }
     546           0 :     _isDone = true;
     547             : 
     548           0 :     if (_subscription == null) {
     549           0 :       return _sourceStream;
     550             :     }
     551             : 
     552           0 :     var subscription = _subscription;
     553           0 :     _subscription = null;
     554             : 
     555           0 :     var wasPaused = subscription.isPaused;
     556           0 :     var result = new SubscriptionStream<T>(subscription);
     557             :     // Resume after creating stream because that pauses the subscription too.
     558             :     // This way there won't be a short resumption in the middle.
     559           0 :     if (wasPaused) subscription.resume();
     560             :     return result;
     561             :   }
     562             : }
     563             : 
     564             : /// A transaction on a [StreamQueue], created by [StreamQueue.startTransaction].
     565             : ///
     566             : /// Copies of the parent queue may be created using [newQueue]. Calling [commit]
     567             : /// moves the parent queue to a copy's position, and calling [reject] causes it
     568             : /// to continue as though [StreamQueue.startTransaction] was never called.
     569             : class StreamQueueTransaction<T> {
     570             :   /// The parent queue on which this transaction is active.
     571             :   final StreamQueue<T> _parent;
     572             : 
     573             :   /// The splitter that produces copies of the parent queue's stream.
     574             :   final StreamSplitter<T> _splitter;
     575             : 
     576             :   /// Queues created using [newQueue].
     577             :   final _queues = new Set<StreamQueue>();
     578             : 
     579             :   /// Whether [commit] has been called.
     580             :   var _committed = false;
     581             : 
     582             :   /// Whether [reject] has been called.
     583             :   var _rejected = false;
     584             : 
     585             :   StreamQueueTransaction._(this._parent, Stream<T> source)
     586           0 :       : _splitter = new StreamSplitter(source);
     587             : 
     588             :   /// Creates a new copy of the parent queue.
     589             :   ///
     590             :   /// This copy starts at the parent queue's position when
     591             :   /// [StreamQueue.startTransaction] was called. Its position can be committed
     592             :   /// to the parent queue using [commit].
     593             :   StreamQueue<T> newQueue() {
     594           0 :     var queue = new StreamQueue(_splitter.split());
     595           0 :     _queues.add(queue);
     596             :     return queue;
     597             :   }
     598             : 
     599             :   /// Commits a queue created using [newQueue].
     600             :   ///
     601             :   /// The parent queue's position is updated to be the same as [queue]'s.
     602             :   /// Further requests on all queues created by this transaction, including
     603             :   /// [queue], will complete as though [cancel] were called with `immediate:
     604             :   /// true`.
     605             :   ///
     606             :   /// Throws a [StateError] if [commit] or [reject] have already been called, or
     607             :   /// if there are pending requests on [queue].
     608             :   void commit(StreamQueue<T> queue) {
     609           0 :     _assertActive();
     610           0 :     if (!_queues.contains(queue)) {
     611           0 :       throw new ArgumentError("Queue doesn't belong to this transaction.");
     612           0 :     } else if (queue._requestQueue.isNotEmpty) {
     613           0 :       throw new StateError("A queue with pending requests can't be committed.");
     614             :     }
     615           0 :     _committed = true;
     616             : 
     617             :     // Remove all events from the parent queue that were consumed by the
     618             :     // child queue.
     619           0 :     for (var j = 0; j < queue.eventsDispatched; j++) {
     620           0 :       _parent._eventQueue.removeFirst();
     621             :     }
     622             : 
     623           0 :     _done();
     624             :   }
     625             : 
     626             :   /// Rejects this transaction without updating the parent queue.
     627             :   ///
     628             :   /// The parent will continue as though [StreamQueue.startTransaction] hadn't
     629             :   /// been called. Further requests on all queues created by this transaction
     630             :   /// will complete as though [cancel] were called with `immediate: true`.
     631             :   ///
     632             :   /// Throws a [StateError] if [commit] or [reject] have already been called.
     633             :   void reject() {
     634           0 :     _assertActive();
     635           0 :     _rejected = true;
     636           0 :     _done();
     637             :   }
     638             : 
     639             :   // Cancels all [_queues], removes the [_TransactionRequest] from [_parent]'s
     640             :   // request queue, and runs the next request.
     641             :   void _done() {
     642           0 :     _splitter.close();
     643           0 :     for (var queue in _queues) {
     644           0 :       queue._cancel();
     645             :     }
     646             : 
     647             :     assert((_parent._requestQueue.first as _TransactionRequest).transaction ==
     648             :         this);
     649           0 :     _parent._requestQueue.removeFirst();
     650           0 :     _parent._updateRequests();
     651             :   }
     652             : 
     653             :   /// Throws a [StateError] if [accept] or [reject] has already been called.
     654             :   void _assertActive() {
     655           0 :     if (_committed) {
     656           0 :       throw new StateError("This transaction has already been accepted.");
     657           0 :     } else if (_rejected) {
     658           0 :       throw new StateError("This transaction has already been rejected.");
     659             :     }
     660             :   }
     661             : }
     662             : 
     663             : /// Request object that receives events when they arrive, until fulfilled.
     664             : ///
     665             : /// Each request that cannot be fulfilled immediately is represented by
     666             : /// an `_EventRequest` object in the request queue.
     667             : ///
     668             : /// Events from the source stream are sent to the first request in the
     669             : /// queue until it reports itself as [isComplete].
     670             : ///
     671             : /// When the first request in the queue `isComplete`, either when becoming
     672             : /// the first request or after receiving an event, its [close] methods is
     673             : /// called.
     674             : ///
     675             : /// The [close] method is also called immediately when the source stream
     676             : /// is done.
     677             : abstract class _EventRequest<T> {
     678             :   /// Handle available events.
     679             :   ///
     680             :   /// The available events are provided as a queue. The `update` function
     681             :   /// should only remove events from the front of the event queue, e.g.,
     682             :   /// using [removeFirst].
     683             :   ///
     684             :   /// Returns `true` if the request is completed, or `false` if it needs
     685             :   /// more events.
     686             :   /// The call may keep events in the queue until the requeust is complete,
     687             :   /// or it may remove them immediately.
     688             :   ///
     689             :   /// If the method returns true, the request is considered fulfilled, and
     690             :   /// will never be called again.
     691             :   ///
     692             :   /// This method is called when a request reaches the front of the request
     693             :   /// queue, and if it returns `false`, it's called again every time a new event
     694             :   /// becomes available, or when the stream closes.
     695             :   /// If the function returns `false` when the stream has already closed
     696             :   /// ([isDone] is true), then the request must call
     697             :   /// [StreamQueue._updateRequests] itself when it's ready to continue.
     698             :   bool update(QueueList<Result<T>> events, bool isDone);
     699             : }
     700             : 
     701             : /// Request for a [StreamQueue.next] call.
     702             : ///
     703             : /// Completes the returned future when receiving the first event,
     704             : /// and is then complete.
     705             : class _NextRequest<T> implements _EventRequest<T> {
     706             :   /// Completer for the future returned by [StreamQueue.next].
     707             :   final _completer = new Completer<T>();
     708             : 
     709           0 :   _NextRequest();
     710             : 
     711           0 :   Future<T> get future => _completer.future;
     712             : 
     713             :   bool update(QueueList<Result<T>> events, bool isDone) {
     714           0 :     if (events.isNotEmpty) {
     715           0 :       events.removeFirst().complete(_completer);
     716             :       return true;
     717             :     }
     718             :     if (isDone) {
     719           0 :       _completer.completeError(
     720           0 :           new StateError("No elements"), StackTrace.current);
     721             :       return true;
     722             :     }
     723             :     return false;
     724             :   }
     725             : }
     726             : 
     727             : /// Request for a [StreamQueue.peek] call.
     728             : ///
     729             : /// Completes the returned future when receiving the first event,
     730             : /// and is then complete, but doesn't consume the event.
     731             : class _PeekRequest<T> implements _EventRequest<T> {
     732             :   /// Completer for the future returned by [StreamQueue.next].
     733             :   final _completer = new Completer<T>();
     734             : 
     735           0 :   _PeekRequest();
     736             : 
     737           0 :   Future<T> get future => _completer.future;
     738             : 
     739             :   bool update(QueueList<Result<T>> events, bool isDone) {
     740           0 :     if (events.isNotEmpty) {
     741           0 :       events.first.complete(_completer);
     742             :       return true;
     743             :     }
     744             :     if (isDone) {
     745           0 :       _completer.completeError(
     746           0 :           new StateError("No elements"), StackTrace.current);
     747             :       return true;
     748             :     }
     749             :     return false;
     750             :   }
     751             : }
     752             : 
     753             : /// Request for a [StreamQueue.skip] call.
     754             : class _SkipRequest<T> implements _EventRequest<T> {
     755             :   /// Completer for the future returned by the skip call.
     756             :   final _completer = new Completer<int>();
     757             : 
     758             :   /// Number of remaining events to skip.
     759             :   ///
     760             :   /// The request [isComplete] when the values reaches zero.
     761             :   ///
     762             :   /// Decremented when an event is seen.
     763             :   /// Set to zero when an error is seen since errors abort the skip request.
     764             :   int _eventsToSkip;
     765             : 
     766           0 :   _SkipRequest(this._eventsToSkip);
     767             : 
     768             :   /// The future completed when the correct number of events have been skipped.
     769           0 :   Future<int> get future => _completer.future;
     770             : 
     771             :   bool update(QueueList<Result<T>> events, bool isDone) {
     772           0 :     while (_eventsToSkip > 0) {
     773           0 :       if (events.isEmpty) {
     774             :         if (isDone) break;
     775             :         return false;
     776             :       }
     777           0 :       _eventsToSkip--;
     778             : 
     779           0 :       var event = events.removeFirst();
     780           0 :       if (event.isError) {
     781           0 :         _completer.completeError(event.asError.error, event.asError.stackTrace);
     782             :         return true;
     783             :       }
     784             :     }
     785           0 :     _completer.complete(_eventsToSkip);
     786             :     return true;
     787             :   }
     788             : }
     789             : 
     790             : /// Common superclass for [_TakeRequest] and [_LookAheadRequest].
     791             : abstract class _ListRequest<T> implements _EventRequest<T> {
     792             :   /// Completer for the future returned by the take call.
     793             :   final _completer = new Completer<List<T>>();
     794             : 
     795             :   /// List collecting events until enough have been seen.
     796             :   final _list = <T>[];
     797             : 
     798             :   /// Number of events to capture.
     799             :   ///
     800             :   /// The request [isComplete] when the length of [_list] reaches
     801             :   /// this value.
     802             :   final int _eventsToTake;
     803             : 
     804           0 :   _ListRequest(this._eventsToTake);
     805             : 
     806             :   /// The future completed when the correct number of events have been captured.
     807           0 :   Future<List<T>> get future => _completer.future;
     808             : }
     809             : 
     810             : /// Request for a [StreamQueue.take] call.
     811             : class _TakeRequest<T> extends _ListRequest<T> {
     812           0 :   _TakeRequest(int eventsToTake) : super(eventsToTake);
     813             : 
     814             :   bool update(QueueList<Result<T>> events, bool isDone) {
     815           0 :     while (_list.length < _eventsToTake) {
     816           0 :       if (events.isEmpty) {
     817             :         if (isDone) break;
     818             :         return false;
     819             :       }
     820             : 
     821           0 :       var event = events.removeFirst();
     822           0 :       if (event.isError) {
     823           0 :         event.asError.complete(_completer);
     824             :         return true;
     825             :       }
     826           0 :       _list.add(event.asValue.value);
     827             :     }
     828           0 :     _completer.complete(_list);
     829             :     return true;
     830             :   }
     831             : }
     832             : 
     833             : /// Request for a [StreamQueue.lookAhead] call.
     834             : class _LookAheadRequest<T> extends _ListRequest<T> {
     835           0 :   _LookAheadRequest(int eventsToTake) : super(eventsToTake);
     836             : 
     837             :   bool update(QueueList<Result<T>> events, bool isDone) {
     838           0 :     while (_list.length < _eventsToTake) {
     839           0 :       if (events.length == _list.length) {
     840             :         if (isDone) break;
     841             :         return false;
     842             :       }
     843           0 :       var event = events.elementAt(_list.length);
     844           0 :       if (event.isError) {
     845           0 :         event.asError.complete(_completer);
     846             :         return true;
     847             :       }
     848           0 :       _list.add(event.asValue.value);
     849             :     }
     850           0 :     _completer.complete(_list);
     851             :     return true;
     852             :   }
     853             : }
     854             : 
     855             : /// Request for a [StreamQueue.cancel] call.
     856             : ///
     857             : /// The request needs no events, it just waits in the request queue
     858             : /// until all previous events are fulfilled, then it cancels the stream queue
     859             : /// source subscription.
     860             : class _CancelRequest<T> implements _EventRequest<T> {
     861             :   /// Completer for the future returned by the `cancel` call.
     862             :   final _completer = new Completer();
     863             : 
     864             :   ///
     865             :   /// When the event is completed, it needs to cancel the active subscription
     866             :   /// of the `StreamQueue` object, if any.
     867             :   final StreamQueue _streamQueue;
     868             : 
     869           0 :   _CancelRequest(this._streamQueue);
     870             : 
     871             :   /// The future completed when the cancel request is completed.
     872           0 :   Future get future => _completer.future;
     873             : 
     874             :   bool update(QueueList<Result<T>> events, bool isDone) {
     875           0 :     if (_streamQueue._isDone) {
     876           0 :       _completer.complete();
     877             :     } else {
     878           0 :       _streamQueue._ensureListening();
     879           0 :       _completer.complete(_streamQueue._extractStream().listen(null).cancel());
     880             :     }
     881             :     return true;
     882             :   }
     883             : }
     884             : 
     885             : /// Request for a [StreamQueue.rest] call.
     886             : ///
     887             : /// The request is always complete, it just waits in the request queue
     888             : /// until all previous events are fulfilled, then it takes over the
     889             : /// stream events subscription and creates a stream from it.
     890             : class _RestRequest<T> implements _EventRequest<T> {
     891             :   /// Completer for the stream returned by the `rest` call.
     892             :   final _completer = new StreamCompleter<T>();
     893             : 
     894             :   /// The [StreamQueue] object that has this request queued.
     895             :   ///
     896             :   /// When the event is completed, it needs to cancel the active subscription
     897             :   /// of the `StreamQueue` object, if any.
     898             :   final StreamQueue<T> _streamQueue;
     899             : 
     900           0 :   _RestRequest(this._streamQueue);
     901             : 
     902             :   /// The stream which will contain the remaining events of [_streamQueue].
     903           0 :   Stream<T> get stream => _completer.stream;
     904             : 
     905             :   bool update(QueueList<Result<T>> events, bool isDone) {
     906           0 :     if (events.isEmpty) {
     907           0 :       if (_streamQueue._isDone) {
     908           0 :         _completer.setEmpty();
     909             :       } else {
     910           0 :         _completer.setSourceStream(_streamQueue._extractStream());
     911             :       }
     912             :     } else {
     913             :       // There are prefetched events which needs to be added before the
     914             :       // remaining stream.
     915           0 :       var controller = new StreamController<T>();
     916           0 :       for (var event in events) {
     917           0 :         event.addTo(controller);
     918             :       }
     919             :       controller
     920           0 :           .addStream(_streamQueue._extractStream(), cancelOnError: false)
     921           0 :           .whenComplete(controller.close);
     922           0 :       _completer.setSourceStream(controller.stream);
     923             :     }
     924             :     return true;
     925             :   }
     926             : }
     927             : 
     928             : /// Request for a [StreamQueue.hasNext] call.
     929             : ///
     930             : /// Completes the [future] with `true` if it sees any event,
     931             : /// but doesn't consume the event.
     932             : /// If the request is closed without seeing an event, then
     933             : /// the [future] is completed with `false`.
     934             : class _HasNextRequest<T> implements _EventRequest<T> {
     935             :   final _completer = new Completer<bool>();
     936             : 
     937           0 :   Future<bool> get future => _completer.future;
     938             : 
     939             :   bool update(QueueList<Result<T>> events, bool isDone) {
     940           0 :     if (events.isNotEmpty) {
     941           0 :       _completer.complete(true);
     942             :       return true;
     943             :     }
     944             :     if (isDone) {
     945           0 :       _completer.complete(false);
     946             :       return true;
     947             :     }
     948             :     return false;
     949             :   }
     950             : }
     951             : 
     952             : /// Request for a [StreamQueue.startTransaction] call.
     953             : ///
     954             : /// This request isn't complete until the user calls
     955             : /// [StreamQueueTransaction.commit] or [StreamQueueTransaction.reject], at which
     956             : /// point it manually removes itself from the request queue and calls
     957             : /// [StreamQueue._updateRequests].
     958             : class _TransactionRequest<T> implements _EventRequest<T> {
     959             :   /// The transaction created by this request.
     960           0 :   StreamQueueTransaction<T> get transaction => _transaction;
     961             :   StreamQueueTransaction<T> _transaction;
     962             : 
     963             :   /// The controller that passes events to [transaction].
     964             :   final _controller = new StreamController<T>(sync: true);
     965             : 
     966             :   /// The number of events passed to [_controller] so far.
     967             :   var _eventsSent = 0;
     968             : 
     969           0 :   _TransactionRequest(StreamQueue<T> parent) {
     970           0 :     _transaction = new StreamQueueTransaction._(parent, _controller.stream);
     971             :   }
     972             : 
     973             :   bool update(QueueList<Result<T>> events, bool isDone) {
     974           0 :     while (_eventsSent < events.length) {
     975           0 :       events[_eventsSent++].addTo(_controller);
     976             :     }
     977           0 :     if (isDone && !_controller.isClosed) _controller.close();
     978             :     return false;
     979             :   }
     980             : }

Generated by: LCOV version 1.13