Skip to main content

io_imap/
coroutine.rs

1//! Generator-shape coroutine driver. Mirrors `core::ops::Coroutine`:
2//! `Yield` for intermediate progress, `Return` for terminal output,
3//! [`ImapCoroutineState`] for both.
4
5use alloc::vec::Vec;
6
7use imap_codec::fragmentizer::Fragmentizer;
8
9/// Result of one [`ImapCoroutine::resume`] step.
10#[derive(Debug)]
11pub enum ImapCoroutineState<Y, R> {
12    Yielded(Y),
13    Complete(R),
14}
15
16pub trait ImapCoroutine {
17    type Yield;
18    type Return;
19
20    /// Pass `None` initially or after a `WantsWrite`, `Some(bytes)`
21    /// after a `WantsRead`, `Some(&[])` on EOF.
22    fn resume(
23        &mut self,
24        fragmentizer: &mut Fragmentizer,
25        arg: Option<&[u8]>,
26    ) -> ImapCoroutineState<Self::Yield, Self::Return>;
27}
28
29/// Standard socket-I/O yield variants; pick another type when extra
30/// variants (events, etc.) are needed.
31#[derive(Debug)]
32pub enum ImapYield {
33    WantsRead,
34    WantsWrite(Vec<u8>),
35}
36
37/// Coroutine `?`: forwards `Yielded` (via `Into`), short-circuits on
38/// `Err`, evaluates to the inner `Ok` value.
39#[macro_export]
40macro_rules! imap_try {
41    ($coroutine:expr, $frag:expr, $arg:expr $(,)?) => {
42        match $crate::coroutine::ImapCoroutine::resume($coroutine, $frag, $arg) {
43            $crate::coroutine::ImapCoroutineState::Yielded(y) => {
44                return $crate::coroutine::ImapCoroutineState::Yielded(y.into());
45            }
46            $crate::coroutine::ImapCoroutineState::Complete(Err(err)) => {
47                return $crate::coroutine::ImapCoroutineState::Complete(Err(err.into()));
48            }
49            $crate::coroutine::ImapCoroutineState::Complete(Ok(value)) => value,
50        }
51    };
52}