isolateChannel<T, U> function

Future<(IsolateSender<T>, IsolateReceiver<U>)> isolateChannel<T, U>(
  1. FutureOr<void> func(
    1. IsolateSender<U> tx,
    2. IsolateReceiver<T> rx
    ), {
  2. SendCodec<T>? toIsolateCodec,
  3. SendCodec<U>? fromIsolateCodec,
})

isolateChannel is used for bi-directional isolate communication. The returned Sender and Receiver can communicate with the spawned isolate and the spawned isolate is passed a Sender and Receiver to communicate with the original isolate. Each item T sent by a Sender will only be seen once by the corresponding Receiver. If the Sender calls close while the Receiver's buffer is not empty, the Receiver will still yield the remaining items in the buffer until empty. Types that can be sent over a SendPort, as defined here https://api.flutter.dev/flutter/dart-isolate/SendPort/send.html , are allow to be sent between isolates. Otherwise a toIsolateCodec and/or a fromIsolateCodec can be passed to encode and decode the messages.

Implementation

Future<(IsolateSender<T> tx, IsolateReceiver<U> rx)> isolateChannel<T, U>(
    FutureOr<void> Function(IsolateSender<U> tx, IsolateReceiver<T> rx) func,
    {SendCodec<T>? toIsolateCodec,
    SendCodec<U>? fromIsolateCodec}) async {
  final receiveFromIsolate = RawReceivePort();
  SendPort? sendToIsolate;
  receiveFromIsolate.handler = (sendPort) {
    sendToIsolate = sendPort as SendPort;
  };
  void startIsolate(SendPort sendToMain) async {
    final receiveFromMain = ReceivePort();
    sendToMain.send(receiveFromMain.sendPort);

    final isolateReceiver = IsolateReceiver._(toIsolateCodec, receiveFromMain);
    final isolateSender = IsolateSender._(fromIsolateCodec, sendToMain);

    try {
      await func(isolateSender, isolateReceiver);
    } finally {
      isolateSender._sPort.send(const _CloseSignal());
      receiveFromMain.close();
    }
  }

  try {
    await Isolate.spawn(startIsolate, (receiveFromIsolate.sendPort));
  } catch (e) {
    receiveFromIsolate.close();
    rethrow;
  }

  // Work-around for not being able to pass Completers since 'dart:async` is now unsendable.
  // Should only loop zero to two times based on Dart's async scheduler.
  while (sendToIsolate == null) {
    await Future.delayed(Duration.zero);
  }

  final receiver = IsolateReceiver._(
      fromIsolateCodec, ReceivePort.fromRawReceivePort(receiveFromIsolate));
  final sender = IsolateSender._(toIsolateCodec, sendToIsolate!);

  return (sender, receiver);
}