pub(crate) enum Plan {
WriteNow(Bytes),
Nothing,
Terminal,
RejectStream {
code: u64,
},
OpenStreamAfter {
after: Duration,
},
SerializeStreamAfter {
target: StreamKey,
},
CloseSession {
code: u32,
reason: Bytes,
},
}Expand description
The wire operation execute has decided on but not performed.
This module owns what the bytes are; session.rs owns the transport
handle and the await. Keeping the split here is what lets every rule
below be unit-tested with no QUIC, no runtime and no session — the same
argument egress.rs makes for its egress::EgressSink.
Variants§
WriteNow(Bytes)
Hand these bytes to the transport now: send.write_all on a stream
site, send_datagram at the datagram site.
A failure at the datagram site is a Reporter::failed, not a
session teardown: one undeliverable datagram must not take the
session with it.
Nothing
Nothing goes to the wire on this call. The unit was queued behind something already waiting, elided, or the site carries no bytes.
Terminal
A positional terminal is now at the tail of the queue. Drain
honouring release times; the drain returns
DrainOutcome::Terminated { forwarded, code } and the stream is
over — do not finish() it.
RejectStream
Do not forward this stream. Stop the source with code; at
StreamSite::Header also reset the destination, which already
exists and has carried nothing.
OpenStreamAfter
Forward this stream, but do not call dest.open_uni() until after
has elapsed. Only StreamSite::Open can produce this — by the
header site the peer stream exists, and that site refuses
StreamAction::OpenAfter with
Refusal::WrongSite rather
than accepting a deferral it cannot perform.
session.rs’s unidirectional accept loop consumes it, and the
deferral reaches the wire: the stream is spawned with no
destination handle, and the per-stream task sleeps after — racing
the session’s cancellation — before it opens one. Nothing is read
from the source in the meantime, so the peer sees no stream at all
for after and then a whole one.
The open happens inside the task but still before the first source byte is read, which is what keeps the two reject sites different on this topology too: by the time the header decision is taken the peer stream exists, so a rejection there still resets it.
SerializeStreamAfter
Forward this stream, but write nothing on it until target has
ended. An unknown or already-ended target proceeds immediately and
reports SerializeTargetUnknown once.
Consumed at both stream sites, because it defers the first write
rather than the stream’s existence: from the open site it is carried
into the pipe, which waits before reading; at the header site the
wait happens in the FramerOut::Header arm, ahead of the header’s
own bytes. Either way the peer stream is already open and silent.
One stream never waits: the unidirectional control stream of a draft whose control plane is a pair of them. Holding its first write would hold SETUP, and the session with it.
CloseSession
A session close was recorded in the SessionCloser, and the
session token is already cancelled — SessionCloser::request
cancels as it records, so the caller does not have to. Return from
the forwarding task; run_with_transport reads the code and reason
back out of the closer at session.rs:255-256.
The unit itself is not forwarded: the hook returned a close instead of an action on it.