Skip to main content

io_smtp/
coroutine.rs

1//! Generator-shape coroutine driver. 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 driver 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    /// Driver should read more bytes and feed them back on resume.
33    WantsRead,
34    /// Driver should write these bytes; the next resume takes `None`.
35    WantsWrite(Vec<u8>),
36}
37
38/// Coroutine `?`: forwards `Yielded` (via `Into`), short-circuits
39/// on `Err`, evaluates to the inner `Ok` value.
40#[macro_export]
41macro_rules! smtp_try {
42    ($coroutine:expr, $arg:expr $(,)?) => {
43        match $crate::coroutine::SmtpCoroutine::resume($coroutine, $arg) {
44            $crate::coroutine::SmtpCoroutineState::Yielded(y) => {
45                return $crate::coroutine::SmtpCoroutineState::Yielded(y.into());
46            }
47            $crate::coroutine::SmtpCoroutineState::Complete(Err(err)) => {
48                return $crate::coroutine::SmtpCoroutineState::Complete(Err(err.into()));
49            }
50            $crate::coroutine::SmtpCoroutineState::Complete(Ok(value)) => value,
51        }
52    };
53}