io_http/coroutine.rs
1//! Generator-shape coroutine driver mirroring `core::ops::Coroutine`:
2//! `Yield` associated type for intermediate progress, `Return` for
3//! terminal output, and a two-variant [`HttpCoroutineState`]
4//! (`Yielded` / `Complete`).
5
6use alloc::vec::Vec;
7
8/// State yielded by an [`HttpCoroutine::resume`] step.
9#[derive(Debug)]
10pub enum HttpCoroutineState<Y, R> {
11 /// Intermediate step: the coroutine needs the caller to perform
12 /// the carried I/O request before the next resume.
13 Yielded(Y),
14 /// Terminal step: the coroutine is done and carries its final
15 /// output or error.
16 Complete(R),
17}
18
19/// Standard-shape HTTP coroutine: own internal state, declare per-step
20/// `Yield`, return `Result<Output, Error>` on completion.
21pub trait HttpCoroutine {
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. Pass [`None`] initially or after [`HttpYield::WantsWrite`];
28 /// pass `Some(data)` after [`HttpYield::WantsRead`]; pass `Some(&[])` for EOF.
29 fn resume(&mut self, arg: Option<&[u8]>) -> HttpCoroutineState<Self::Yield, Self::Return>;
30}
31
32/// Standard I/O-only Yield; pick `type Yield = HttpYield` when the
33/// coroutine only reads or writes socket bytes.
34#[derive(Debug)]
35pub enum HttpYield {
36 /// The coroutine wants bytes read from the stream and handed back
37 /// on the next resume.
38 WantsRead,
39 /// The coroutine wants these bytes written to the stream.
40 WantsWrite(Vec<u8>),
41}
42
43/// Coroutine `?`: forwards `Yielded` (via `Into`), short-circuits on
44/// `Err` (via `Into`), evaluates to the inner `Ok` value.
45#[macro_export]
46macro_rules! http_try {
47 ($coroutine:expr, $arg:expr $(,)?) => {
48 match $crate::coroutine::HttpCoroutine::resume($coroutine, $arg) {
49 $crate::coroutine::HttpCoroutineState::Yielded(y) => {
50 return $crate::coroutine::HttpCoroutineState::Yielded(y.into());
51 }
52 $crate::coroutine::HttpCoroutineState::Complete(Err(err)) => {
53 return $crate::coroutine::HttpCoroutineState::Complete(Err(err.into()));
54 }
55 $crate::coroutine::HttpCoroutineState::Complete(Ok(value)) => value,
56 }
57 };
58}