API Reference — Tag Identity and Slot Programming
Two rules run through the whole API. Tag identity: what a handle is. Slot rule: where it lives.
Tag identity — class, not instance
PolyHelper(T) generates one static _tag: PolyTag per type T at comptime.
TAG is a pointer to that static — the same address for every instance of T.
Tag dispatch (is_it_you, isIt, fromPoly) answers one question: "is this a T?"
It does not answer: "which T?" or "what role does this T play?"
For user-defined types (Event, Sensor, etc.):
- Tag identifies the class.
- Instance fields carry the role. The user adds a
kindorrolefield to discriminate.
For infra handles (Mbox, Pool):
-
MboxandPoolare public structs, but their fields are internal. The user cannot add fields. -
Tag identifies the class only. No per-instance role information is accessible.
-
Instance identity: resolved by pointer comparison. E.g.
Mbox.mustFromPoly(slot.?) == worker_mbxidentifies which specific
mailbox arrived, comparing two*Mbox. -
Role: established by protocol — the channel the handle arrived on, message ordering, or prior agreement between sender and receiver.
Transporting infra handles — valid patterns
Worker-finish-signal pattern
Master creates worker_mbx, spawns a worker via io.concurrent and passes worker_mbx as parameter.
Worker processes items until a shutdown signal, then:
- Sends
worker_mbx.toPoly()back to master's inbox (unclosed) as the finish signal. - Exits.
Master receives a PolyNode from its inbox:
-
Mbox.mustFromPoly(slot.?)— crosses the border, panics if the node is not a mailbox.Mbox.fromPolyis the checking form, null on mismatch. -
Mbox.mustFromPoly(slot.?) == worker_mbx— confirms instance (it is the expected worker mailbox). Both sides are*Mbox. -
Master closes and destroys
worker_mbx. - Master awaits the worker's future (cleanup only — the mailbox return was the logical finish signal).
This pattern replaces relying on the future await as a completion signal, or a separate shutdown message, with a handle handoff.
Wrapper pattern (for tag-level role discrimination)
When tag dispatch must distinguish roles, wrap the handle in a user-defined PolyNode struct:
const WorkerInbox = struct {
poly: PolyNode,
mbx: *Mbox,
};
pub const WorkerInboxPolyHelper = polynode.PolyHelper(WorkerInbox);
WorkerInboxPolyHelper.TAG is distinct from Mbox.TAG.
The receiver dispatches on WorkerInboxPolyHelper.TAG and finds the embedded *Mbox.