pub trait Link<P>: Protocol<Note = Note> {
// Required methods
fn send(to: NodeId, msg: P) -> Self::Cmd;
fn classify(ind: Self::Ind) -> LinkInd<P>;
}Expand description
What a layer above the link may depend on, and the whole of what it may.
P is the payload the layer above sends. A link is free to wrap it — the perfect link adds a
message identifier — which is why Link::send builds the request rather than the layer above
constructing one, and why Link::classify takes the payload back out.
Satisfying the port is a decision, not an accident of shape. An earlier draft made it a blanket
impl over every Protocol with the right associated types, which meant a protocol became a link
by coincidence; a link now says so. A protocol that has not is rejected when the project is
built:
fn requires_a_link<L: recon_protocols::link::Link<u32>>() {}
requires_a_link::<NotALink>();Required Methods§
Sourcefn send(to: NodeId, msg: P) -> Self::Cmd
fn send(to: NodeId, msg: P) -> Self::Cmd
The request that sends msg to to.
A constructor rather than a fixed type, because the request is the link’s own vocabulary.
Sourcefn classify(ind: Self::Ind) -> LinkInd<P>
fn classify(ind: Self::Ind) -> LinkInd<P>
What this indication means to the layer above.
Total, and deliberately so: a layer above maps its child’s indications with one function, so a link that could report something unclassifiable would leave that layer with a case it could only drop — and silently absorbing a scope end is this project’s cardinal sin.
Dyn Compatibility§
This trait is not dyn compatible.
In older versions of Rust, dyn compatibility was called "object safety".
Implementors§
impl<P: Clone> Link<P> for FairLossLink<P>
The fair-loss link satisfies the link port, and only its unscoped half.
It does not report scope boundaries because it cannot observe any — it holds no session, no epoch and no state whatever. A layer that repairs a scope ending gets nothing from this link, which is the honest outcome rather than a boundary invented to satisfy a bound.
impl<P> Link<P> for PerfectLink<P>where
P: Clone,
The perfect link satisfies the link port, and reports no scope boundary.
Link::classify here never yields
LinkInd::Boundary: PL2’s no-duplication holds within one
incarnation of the recipient, and this link has no means of observing that incarnation ending. A
link that reported a boundary it cannot see would be asserting something it does not know, which
docs/scope-annotated-modules.md forbids by Definition 2a.
Nothing in the type system enforces that, and crate::link records why: a ScopedLink
marker trait existed for exactly this and was deleted for want of a consumer — the one layer
that should have bounded on it could not, because its resend lives in the Link impl and the
tighter bound would have fallen on every link. What keeps it honest instead is the
classification itself, and tests/link_port.rs pins both halves: that this link’s
classification never yields a boundary, and that the session link’s yields one for each variant
that reports it.
impl<P> Link<P> for SessionLink<P>where
P: Clone,
The session link satisfies the link port, and reports scope boundaries through it.
It classifies its two boundary indications as boundaries, which is a claim that it can observe them — and it can: the simulator raises a session ending and an establishment, and this link is where they enter the stack. That is what a layer above needs in order to repair a lost suffix, and what the perfect link cannot offer.