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