async fn forward_uni_streams(
source: &Transport,
dest: Arc<Transport>,
side: ProxySide,
ctx: &ForwardCtx,
control: Option<ControlLeg>,
) -> Result<(), ProxyError>Expand description
Forward unidirectional streams from source to destination.
§Why dest is an Arc and source is not
StreamAction::OpenAfter
defers dest.open_uni() past the accept
loop, into the spawned per-stream task, so the destination transport has
to be shared rather than borrowed for the loop’s lifetime. Both call
sites already hold an Arc<Transport> and Transport is not Clone,
so this is the only shape available. source stays a borrow: nothing is
ever done with it outside the loop.
§The two open topologies, and why the default one did not move
StreamAction::Open
— and therefore every session that never returns
OpenAfter — keeps dest.open_uni() in the accept loop, between the
Site::StreamOpen decision and the spawn, exactly where it has always
been. That is what keeps the two reject sites observably different: a
reject at the open site creates no peer stream at all, while a reject at
the header site resets a peer stream that already exists having carried
nothing. Opening lazily for every stream would collapse that difference
into one behaviour and silently retire a published capability
distinction.
The OpenAfter arm spawns first and opens inside the task, after the
delay — and it opens before the first byte is read, so by the time the
header site is reached the peer stream exists there too and a reject
there still resets it.