io_proxy/coroutine.rs
1//! Generator-shape coroutine driver mirroring `core::ops::Coroutine`:
2//! a `Yield` associated type for intermediate progress, a `Return` for
3//! terminal output, and a two-variant [`ProxyCoroutineState`]
4//! (`Yielded` / `Complete`). Shared by every proxy protocol.
5
6use alloc::vec::Vec;
7
8/// State yielded by a [`ProxyCoroutine::resume`] step.
9#[derive(Debug)]
10pub enum ProxyCoroutineState<Y, R> {
11 /// Intermediate step: the coroutine needs the caller to perform the
12 /// carried I/O request before the next resume.
13 Yielded(Y),
14 /// Terminal step: the coroutine is done and carries its final output
15 /// or error.
16 Complete(R),
17}
18
19/// Standard-shape proxy coroutine: owns its internal state, declares a
20/// per-step `Yield`, and returns `Result<Output, Error>` on completion.
21pub trait ProxyCoroutine {
22 /// The intermediate value emitted on every yielded step.
23 type Yield;
24 /// The terminal value emitted on completion.
25 type Return;
26
27 /// Advances one step.
28 ///
29 /// Pass [`None`] initially and after every [`ProxyYield::WantsWrite`];
30 /// pass `Some(data)` after a [`ProxyYield::WantsRead(n)`] with exactly
31 /// the `n` bytes that were read.
32 ///
33 /// [`ProxyYield::WantsRead(n)`]: ProxyYield::WantsRead
34 fn resume(&mut self, arg: Option<&[u8]>) -> ProxyCoroutineState<Self::Yield, Self::Return>;
35}
36
37/// I/O request emitted by a yielded coroutine step.
38///
39/// [`WantsRead`] carries an exact byte count rather than an open-ended
40/// "read some": the pump reads exactly that many bytes (e.g. via
41/// `read_exact`) and never consumes tunnel payload that arrives right
42/// after the handshake. Length-framed protocols (SOCKS5) request whole
43/// messages; delimiter-framed ones (HTTP CONNECT) request one byte at a
44/// time while scanning.
45///
46/// [`WantsRead`]: ProxyYield::WantsRead
47#[derive(Debug)]
48pub enum ProxyYield {
49 /// The coroutine wants exactly this many bytes read from the stream
50 /// and handed back on the next resume.
51 WantsRead(usize),
52 /// The coroutine wants these bytes written to the stream.
53 WantsWrite(Vec<u8>),
54}