Skip to main content

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}