rpc_dart_isolate
Isolate-based caller/responder transports for rpc_dart.
- VM: spawns isolates and bridges them with stream-ID multiplexing.
- Web/wasm: uses
isolate_managerworkers for parity API. - API:
RpcIsolateTransport.spawnreturns{ transport, kill }pair.
Extracted from rpc_dart_transports to keep web-safe, single-responsibility package.
What crosses the isolate boundary
This transport reports supportsZeroCopy == true, which means sendDirectObject
works here — not that the peer receives the sender's instance. SendPort.send
deep-copies everything that is not deeply immutable. Measured by comparing
identityHashCode on both sides:
| what is sent | result |
|---|---|
| ordinary class built at runtime | copied |
const instance |
shared |
@pragma('vm:deeply-immutable') class |
shared, also when built at runtime |
| an annotated class held by an ordinary message | the message is copied, the annotated field is shared |
Uint8List payload (TransferableTypedData) |
moved, not copied |
Measured end to end through this transport, not just over a raw SendPort; see
test/deeply_immutable_is_shared_test.dart.
Real zero-copy for your messages
Annotate the message class. The pragma is what does it — the same class with the
same final fields and no pragma is copied:
@pragma('vm:deeply-immutable')
final class Tick {
const Tick(this.symbol, this.priceCents);
final String symbol;
final int priceCents;
}
The VM enforces this at compile time. The class must be final or sealed, every
instance field final and non-late, and every field type deeply immutable —
int, double, bool, String, Pointer, Float32x4, Float64x2, Int32x4,
or another vm:deeply-immutable class. List, Map and even Uint8List are
rejected, so bulk data does not travel this way; send it as a payload instead,
which the transport already transfers without a copy.
Every direct object must be SENDABLE
Objects go on the port as they are, so a Future, Timer or ReceivePort
anywhere in the graph makes SendPort.send throw — including in a field your
codec never looks at. That fails the call it belongs to (the connection and other
in-flight calls are unaffected), and the error names the offending field.
Note that a unary call takes this path even when the method declares codecs,
because UnaryCaller branches on the transport's zero-copy support alone.
Libraries
- rpc_dart_isolate
- Isolate transports for rpc_dart (IO + web/wasm).