LCOV - code coverage report
Current view: top level - async-2.5.0/lib/src - cancelable_operation.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 67 0.0 %
Date: 2021-11-28 14:37:50 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             : 
       7             : import 'package:async/async.dart';
       8             : 
       9             : import 'utils.dart';
      10             : 
      11             : /// An asynchronous operation that can be cancelled.
      12             : ///
      13             : /// The value of this operation is exposed as [value]. When this operation is
      14             : /// cancelled, [value] won't complete either successfully or with an error. If
      15             : /// [value] has already completed, cancelling the operation does nothing.
      16             : class CancelableOperation<T> {
      17             :   /// The completer that produced this operation.
      18             :   ///
      19             :   /// This is canceled when [cancel] is called.
      20             :   final CancelableCompleter<T> _completer;
      21             : 
      22           0 :   CancelableOperation._(this._completer);
      23             : 
      24             :   /// Creates a [CancelableOperation] wrapping [inner].
      25             :   ///
      26             :   /// When this operation is canceled, [onCancel] will be called and any value
      27             :   /// or error produced by [inner] will be discarded. If [onCancel] returns a
      28             :   /// [Future], it will be forwarded to [cancel].
      29             :   ///
      30             :   /// [onCancel] will be called synchronously when the operation is canceled.
      31             :   /// It's guaranteed to only be called once.
      32             :   ///
      33             :   /// Calling this constructor is equivalent to creating a [CancelableCompleter]
      34             :   /// and completing it with [inner]. As such, [isCompleted] is true from the
      35             :   /// moment this [CancelableOperation] is created, regardless of whether
      36             :   /// [inner] has completed yet or not.
      37           0 :   factory CancelableOperation.fromFuture(Future<T> inner,
      38             :       {FutureOr Function()? onCancel}) {
      39           0 :     var completer = CancelableCompleter<T>(onCancel: onCancel);
      40           0 :     completer.complete(inner);
      41           0 :     return completer.operation;
      42             :   }
      43             : 
      44             :   /// The value returned by the operation.
      45           0 :   Future<T> get value => _completer._inner.future;
      46             : 
      47             :   /// Creates a [Stream] containing the result of this operation.
      48             :   ///
      49             :   /// This is like `value.asStream()`, but if a subscription to the stream is
      50             :   /// canceled, this is as well.
      51           0 :   Stream<T> asStream() {
      52             :     var controller =
      53           0 :         StreamController<T>(sync: true, onCancel: _completer._cancel);
      54             : 
      55           0 :     value.then((value) {
      56           0 :       controller.add(value);
      57           0 :       controller.close();
      58           0 :     }, onError: (Object error, StackTrace stackTrace) {
      59           0 :       controller.addError(error, stackTrace);
      60           0 :       controller.close();
      61             :     });
      62           0 :     return controller.stream;
      63             :   }
      64             : 
      65             :   /// Creates a [Future] that completes when this operation completes *or* when
      66             :   /// it's cancelled.
      67             :   ///
      68             :   /// If this operation completes, this completes to the same result as [value].
      69             :   /// If this operation is cancelled, the returned future waits for the future
      70             :   /// returned by [cancel], then completes to [cancellationValue].
      71           0 :   Future<T?> valueOrCancellation([T? cancellationValue]) {
      72           0 :     var completer = Completer<T?>.sync();
      73           0 :     value.then((result) => completer.complete(result),
      74           0 :         onError: completer.completeError);
      75             : 
      76           0 :     _completer._cancelMemo.future.then((_) {
      77           0 :       completer.complete(cancellationValue);
      78           0 :     }, onError: completer.completeError);
      79             : 
      80           0 :     return completer.future;
      81             :   }
      82             : 
      83             :   /// Registers callbacks to be called when this operation completes.
      84             :   ///
      85             :   /// [onValue] and [onError] behave in the same way as [Future.then].
      86             :   ///
      87             :   /// If [onCancel] is provided, and this operation is canceled, the [onCancel]
      88             :   /// callback is called and the returned operation completes with the result.
      89             :   ///
      90             :   /// If [onCancel] is not given, and this operation is canceled, then the
      91             :   /// returned operation is canceled.
      92             :   ///
      93             :   /// If [propagateCancel] is `true` and the returned operation is canceled then
      94             :   /// this operation is canceled. The default is `false`.
      95           0 :   CancelableOperation<R> then<R>(FutureOr<R> Function(T) onValue,
      96             :       {FutureOr<R> Function(Object, StackTrace)? onError,
      97             :       FutureOr<R> Function()? onCancel,
      98             :       bool propagateCancel = false}) {
      99             :     final completer =
     100           0 :         CancelableCompleter<R>(onCancel: propagateCancel ? cancel : null);
     101             : 
     102           0 :     valueOrCancellation().then((T? result) {
     103           0 :       if (!completer.isCanceled) {
     104           0 :         if (isCompleted) {
     105           0 :           assert(result is T);
     106           0 :           completer.complete(Future.sync(() => onValue(result as T)));
     107             :         } else if (onCancel != null) {
     108           0 :           completer.complete(Future.sync(onCancel));
     109             :         } else {
     110           0 :           completer._cancel();
     111             :         }
     112             :       }
     113           0 :     }, onError: (Object error, StackTrace stackTrace) {
     114           0 :       if (!completer.isCanceled) {
     115             :         if (onError != null) {
     116           0 :           completer.complete(Future.sync(() => onError(error, stackTrace)));
     117             :         } else {
     118           0 :           completer.completeError(error, stackTrace);
     119             :         }
     120             :       }
     121             :     });
     122           0 :     return completer.operation;
     123             :   }
     124             : 
     125             :   /// Cancels this operation.
     126             :   ///
     127             :   /// This returns the [Future] returned by the [CancelableCompleter]'s
     128             :   /// `onCancel` callback. Unlike [Stream.cancel], it never returns `null`.
     129           0 :   Future cancel() => _completer._cancel();
     130             : 
     131             :   /// Whether this operation has been canceled before it completed.
     132           0 :   bool get isCanceled => _completer.isCanceled;
     133             : 
     134             :   /// Whether the [CancelableCompleter] backing this operation has been
     135             :   /// completed.
     136             :   ///
     137             :   /// This value being true does not imply that the [value] future has
     138             :   /// completed, but merely that it is no longer possible to [cancel] the
     139             :   /// operation.
     140           0 :   bool get isCompleted => _completer.isCompleted;
     141             : }
     142             : 
     143             : /// A completer for a [CancelableOperation].
     144             : class CancelableCompleter<T> {
     145             :   /// The completer for the wrapped future.
     146             :   final _inner = Completer<T>();
     147             : 
     148             :   /// The callback to call if the future is canceled.
     149             :   final FutureOrCallback? _onCancel;
     150             : 
     151             :   /// Creates a new completer for a [CancelableOperation].
     152             :   ///
     153             :   /// When the future operation canceled, as long as the completer hasn't yet
     154             :   /// completed, [onCancel] is called. If [onCancel] returns a [Future], it's
     155             :   /// forwarded to [CancelableOperation.cancel].
     156             :   ///
     157             :   /// [onCancel] will be called synchronously when the operation is canceled.
     158             :   /// It's guaranteed to only be called once.
     159           0 :   CancelableCompleter({FutureOr Function()? onCancel}) : _onCancel = onCancel;
     160             : 
     161             :   /// The operation controlled by this completer.
     162             :   late final operation = CancelableOperation<T>._(this);
     163             : 
     164             :   /// Whether the completer has completed.
     165           0 :   bool get isCompleted => _isCompleted;
     166             :   bool _isCompleted = false;
     167             : 
     168             :   /// Whether the completer was canceled before being completed.
     169           0 :   bool get isCanceled => _isCanceled;
     170             :   bool _isCanceled = false;
     171             : 
     172             :   /// The memoizer for [_cancel].
     173             :   final _cancelMemo = AsyncMemoizer();
     174             : 
     175             :   /// Completes [operation] to [value].
     176             :   ///
     177             :   /// If [value] is a [Future], this will complete to the result of that
     178             :   /// [Future] once it completes.
     179           0 :   void complete([FutureOr<T>? value]) {
     180           0 :     if (_isCompleted) throw StateError('Operation already completed');
     181           0 :     _isCompleted = true;
     182             : 
     183           0 :     if (value is! Future) {
     184           0 :       if (_isCanceled) return;
     185           0 :       _inner.complete(value);
     186             :       return;
     187             :     }
     188             : 
     189             :     final future = value as Future<T>;
     190           0 :     if (_isCanceled) {
     191             :       // Make sure errors from [value] aren't top-leveled.
     192           0 :       future.catchError((_) {});
     193             :       return;
     194             :     }
     195             : 
     196           0 :     future.then((result) {
     197           0 :       if (_isCanceled) return;
     198           0 :       _inner.complete(result);
     199           0 :     }, onError: (Object error, StackTrace stackTrace) {
     200           0 :       if (_isCanceled) return;
     201           0 :       _inner.completeError(error, stackTrace);
     202             :     });
     203             :   }
     204             : 
     205             :   /// Completes [operation] to [error].
     206           0 :   void completeError(Object error, [StackTrace? stackTrace]) {
     207           0 :     if (_isCompleted) throw StateError('Operation already completed');
     208           0 :     _isCompleted = true;
     209             : 
     210           0 :     if (_isCanceled) return;
     211           0 :     _inner.completeError(error, stackTrace);
     212             :   }
     213             : 
     214             :   /// Cancel the completer.
     215           0 :   Future _cancel() {
     216           0 :     if (_inner.isCompleted) return Future.value();
     217             : 
     218           0 :     return _cancelMemo.runOnce(() {
     219           0 :       _isCanceled = true;
     220           0 :       var onCancel = _onCancel;
     221             :       if (onCancel != null) return onCancel();
     222             :     });
     223             :   }
     224             : }

Generated by: LCOV version 1.14