run method

  1. @override
Future<T> run()
override

Executes the computation and returns the computation result (or throws the exception), or throws the CancellationException exception if the terminate method was called before the computation was completed.

Implementation

@override
Future<T> run() async {
  if (_isStarted) {
    throw StateError('The computation can be run only once');
  }

  _isStarted = true;
  if (_isTerminationRequested) {
    throw CancellationException();
  }

  if (_token != null) {
    _token!.throwIfCanceled();
  }

  final completer = Completer<void>();
  var hasResult = false;
  var isCanceled = false;
  T? result;
  Object? error;
  StackTrace? stackTrace;
  final port = RawReceivePort();
  final sendPort = port.sendPort;
  SendPort? remotePort;

  void sendCancellationRequest() {
    remotePort?.send(null);
  }

  void handle(Object? message) {
    if (message is SendPort) {
      remotePort = message;
      return;
    }

    port.close();
    if (message == null) {
      isCanceled = _isTerminationRequested;
    } else if (message is List) {
      error = message[0];
      final stackTraceString = message[1] as String?;
      if (stackTraceString != null && stackTraceString.isNotEmpty) {
        stackTrace = StackTrace.fromString(stackTraceString);
      }
    } else if (message is (String, Object?)) {
      final (event, value) = message;
      switch (event) {
        case 'result':
          hasResult = true;
          result = value as T;
          break;
        case 'cancellation':
          isCanceled = true;
          break;
      }
    }

    _token?.removerHandler(sendCancellationRequest);
    completer.complete();
  }

  port.handler = handle;
  _token?.addHandler(sendCancellationRequest);
  final isolate =
      await Isolate.spawn<(SendPort, FutureOr<T> Function() function)>(
    _compute,
    (sendPort, _computation),
    onError: sendPort,
    onExit: sendPort,
    paused: true,
  );

  _isolate = isolate;
  isolate.resume(isolate.pauseCapability!);
  await completer.future;
  if (error != null) {
    Error.throwWithStackTrace(error!, stackTrace ?? StackTrace.empty);
  } else if (hasResult) {
    return result as T;
  } else if (isCanceled) {
    throw CancellationException();
  } else {
    throw StateError('Computation ended without result');
  }
}