channel
rust supports two types of channels, "local" channels (same isolate) and "isolate" channels (different isolates).
Local Channels
localChannel
is used for communication between produces and consumers on the same isolate. localChannel
is
similar to StreamController
except it buffers data until read and will never throw.
In more detail, localChannel
returns a Sender
and Receiver
. Each item T
sent by the Sender
will only be seen once by the Receiver
. Even 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.
Examples
Single Sender, Single Receiver
import 'package:rust/sync.dart';
void main() async {
final (tx, rx) = localChannel<int>();
// Sender sends data
tx.send(1);
tx.send(2);
tx.send(3);
// Receiver retrieves data
for (int i = 0; i < 3; i++) {
print(await rx.recv()); // Outputs: 1, 2, 3
}
}
Receiver with Timeout
import 'package:rust/sync.dart';
void main() async {
final (tx, rx) = localChannel<int>();
// Sender sends data
tx.send(1);
// Receiver retrieves data with a timeout
final result = await rx.recvTimeout(Duration(milliseconds: 100));
if (result.isOk()) {
print(result.unwrap()); // Outputs: 1
} else {
print("Timeout"); // If timeout occurs
}
}
Receiver with Error Handling
import 'package:rust/sync.dart';
void main() async {
final (tx, rx) = localChannel<int>();
// Sender sends data and then an error
tx.send(1);
tx.send(2);
tx.sendError(Exception("Test error"));
// Receiver retrieves data and handles errors
for (int i = 0; i < 3; i++) {
final result = await rx.recv();
if (result.isOk()) {
print(result.unwrap()); // Outputs: 1, 2
} else {
print("Error: ${result.unwrapErr()}"); // Handles error
}
}
}
Iterating Over Received Data
import 'package:rust/sync.dart';
void main() async {
final (tx, rx) = localChannel<int>();
// Sender sends data
tx.send(1);
tx.send(2);
tx.send(3);
// Receiver iterates over the data
final iterator = rx.iter();
for (final value in iterator) {
print(value); // Outputs: 1, 2, 3
}
}
Using Receiver as a Stream
import 'package:rust/sync.dart';
void main() async {
final (tx, rx) = localChannel<int>();
// Sender sends data
tx.send(1);
tx.send(2);
tx.send(3);
// Close the sender after some delay
() async {
await Future.delayed(Duration(seconds: 1));
tx.close();
}();
// Receiver processes the stream of data
await for (final value in rx.stream()) {
print(value); // Outputs: 1, 2, 3
}
}
Isolate Channels
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 the Sender
will only be seen once by the Receiver
. Even 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,
are allow to be sent between isolates. Otherwise a toSpawnedCodec
and/or a fromSpawnedCodec
can be passed
to encode and decode the messages.
Note: Dart does not support isolates on web. Therefore, if your compilation target is web, you cannot use
isolateChannel
.
Examples
Simple String Communication
void main() async {
final (tx, rx) = await isolateChannel<String, String>((tx, rx) async {
assert((await rx.recv()).unwrap() == "hello");
tx.send("hi");
});
tx.send("hello");
expect((await rx.recv()).unwrap(), "hi");
}
Explicitly Defined Codecs for Communication
void main() async {
final (tx, rx) = await isolateChannel<String, int>((tx, rx) async {
assert((await rx.recv()).unwrap() == "hello");
tx.send(1);
}, toSpawnedCodec: const StringCodec(), fromSpawnedCodec: const IntCodec());
tx.send("hello");
expect((await rx.recv()).unwrap(), 1);
}