PullSubscriber class

A zenoh pull subscriber: samples accumulate in a bounded channel and the caller takes them out on demand.

Unlike Subscriber, which pushes samples into a stream as they arrive, a PullSubscriber buffers them and hands them over one at a time when tryRecv is called — so the consumer sets the pace.

The kind chosen at declaration decides what happens when the buffer fills: ChannelKind.ring drops the oldest sample and never blocks the publisher, ChannelKind.fifo keeps every sample and blocks the publisher instead. The kinds also differ at the END of a channel's life: when the producer dies, a fifo drains what it still holds before reporting disconnected, while a ring discards it. Both behaviours are canon's own, measured at 1.8.0, and rendered here unsmoothed.

Drain only if the residue matters. close releases the channel with whatever it still holds — our handle owns both halves, so there is no post-close drain window. Poll to exhaustion first if you need those samples.

⚠️ This used to read "drain before you close", and it silently carried a CORRECTNESS claim it could not honour. Closing an undrained, overflowing fifo once hung the calling isolate permanently. That is fixed at the source — close now releases the receiving end before undeclaring — and draining could never have prevented it from one isolate anyway: measured at canon level, the hang persisted even after the producer was gone. Draining is residue guidance, and nothing more.

⚠️ One teardown ORDER still matters, and it is canon's, not this binding's: close pull handles before closing their session when a fifo may be in overflow. A session closed first still stalls — measured, and pinned as a residual in test/fifo_close_deadlock_test.dart. This unit does not fix that path.

Call close when done to undeclare the subscriber and release native resources.

This object holds a native handle, so it cannot cross an isolate boundary: a copy would share this one's native address while carrying its own fresh disposal flag, and the second release would be a use-after-free. Sending it throws ArgumentError naming the class.

No NativeFinalizer is attached to this class, deliberately: its close() is seven steps of which four are Dart-side — completing a pending waiter, releasing the demand gate, closing a ReceivePort — and a finalizer callback has no isolate to run them in. It is also never collected in practice, so a finalizer there would be dead code. Releasing it explicitly is therefore the only thing that reclaims it.

Implemented types

Constructors

PullSubscriber(Pointer<Uint8> _subscriberHandle, Pointer<Uint8> _handlerHandle, Pointer<Uint8> _teeHandle, ReceivePort _receivePort, String _keyExpr, ChannelKind _kind, [bool _retainPayload = false])
Internal constructor. Use Session.declarePullSubscriber instead.

Properties

hashCode int
The hash code for this object.
no setterinherited
keyExpr String
The key expression this pull subscriber is declared on.
no setter
kind ChannelKind
The bounded channel kind backing this subscriber.
no setter
runtimeType Type
A representation of the runtime type of the object.
no setterinherited
stream Stream<Sample>
A bounded, demand-gated Stream view over this handle's own recv.
no setter

Methods

close() → void
Closes the pull subscriber and releases native resources.
noSuchMethod(Invocation invocation) → dynamic
Invoked when a nonexistent method or property is accessed.
inherited
recv() Future<RecvResult<Sample>>
Waits for the next sample.
toString() String
A string representation of this object.
inherited
tryRecv() RecvResult<Sample>
Tries to receive a sample, without waiting.

Operators

operator ==(Object other) bool
The equality operator.
inherited