Skip to main content

io_smtp/
coroutine.rs

1//! Generator-shape coroutine contract. Mirrors `core::ops::Coroutine`:
2//! `Yield` for intermediate progress, `Return` for terminal output,
3//! [`SmtpCoroutineState`] for both.
4
5use alloc::vec::Vec;
6
7/// State yielded by an [`SmtpCoroutine::resume`] step.
8#[derive(Debug)]
9pub enum SmtpCoroutineState<Y, R> {
10    /// Intermediate yield; the caller reacts and resumes.
11    Yielded(Y),
12    /// Terminal yield; by convention `R = Result<Output, Error>`.
13    Complete(R),
14}
15
16/// Standard-shape SMTP coroutine.
17pub trait SmtpCoroutine {
18    /// Per-step value.
19    type Yield;
20    /// Terminal value; by convention `Result<Output, Error>`.
21    type Return;
22
23    /// Advances the coroutine one step. Pass `None` for the initial
24    /// call or after a [`SmtpYield::WantsWrite`]; `Some(data)` after
25    /// a [`SmtpYield::WantsRead`]; `Some(&[])` to signal EOF.
26    fn resume(&mut self, arg: Option<&[u8]>) -> SmtpCoroutineState<Self::Yield, Self::Return>;
27}
28
29/// Standard I/O-only Yield; every coroutine in this crate picks it.
30#[derive(Debug)]
31pub enum SmtpYield {
32    /// The caller should read more bytes and feed them back on
33    /// resume.
34    WantsRead,
35    /// The caller should write these bytes; the next resume takes
36    /// `None`.
37    WantsWrite(Vec<u8>),
38}
39
40/// Coroutine `?`: forwards `Yielded` (via `Into`), short-circuits
41/// on `Err`, evaluates to the inner `Ok` value.
42#[macro_export]
43macro_rules! smtp_try {
44    ($coroutine:expr, $arg:expr $(,)?) => {
45        match $crate::coroutine::SmtpCoroutine::resume($coroutine, $arg) {
46            $crate::coroutine::SmtpCoroutineState::Yielded(y) => {
47                return $crate::coroutine::SmtpCoroutineState::Yielded(y.into());
48            }
49            $crate::coroutine::SmtpCoroutineState::Complete(Err(err)) => {
50                return $crate::coroutine::SmtpCoroutineState::Complete(Err(err.into()));
51            }
52            $crate::coroutine::SmtpCoroutineState::Complete(Ok(value)) => value,
53        }
54    };
55}