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 : }
|