io_imap/coroutine.rs
1//! Generator-shape coroutine contract, mirroring `core::ops::Coroutine`.
2//!
3//! `Yield` covers intermediate progress, `Return` the terminal output,
4//! [`ImapCoroutineState`] both.
5
6use alloc::vec::Vec;
7
8use imap_codec::fragmentizer::Fragmentizer;
9
10/// Result of one [`ImapCoroutine::resume`] step.
11#[derive(Debug)]
12pub enum ImapCoroutineState<Y, R> {
13 /// The coroutine needs I/O (or emitted an event) before it can
14 /// progress.
15 Yielded(Y),
16 /// The coroutine is done; resuming it again is a logic error.
17 Complete(R),
18}
19
20/// An I/O-free IMAP coroutine, resumed with the connection-wide
21/// `Fragmentizer` and the bytes read by the caller.
22pub trait ImapCoroutine {
23 /// The request type yielded while the coroutine progresses.
24 type Yield;
25
26 /// The final value produced on completion.
27 type Return;
28
29 /// Pass `None` initially or after a `WantsWrite`, `Some(bytes)`
30 /// after a `WantsRead`, `Some(&[])` on EOF.
31 fn resume(
32 &mut self,
33 fragmentizer: &mut Fragmentizer,
34 arg: Option<&[u8]>,
35 ) -> ImapCoroutineState<Self::Yield, Self::Return>;
36}
37
38/// Standard socket-I/O yield variants; pick another type when extra
39/// variants (events, etc.) are needed.
40#[derive(Debug)]
41pub enum ImapYield {
42 /// The caller reads from its stream and resumes with the bytes.
43 WantsRead,
44 /// The caller writes the given bytes to its stream and resumes.
45 WantsWrite(Vec<u8>),
46}
47
48/// Coroutine `?`: forwards `Yielded` (via `Into`), short-circuits on
49/// `Err`, evaluates to the inner `Ok` value.
50#[macro_export]
51macro_rules! imap_try {
52 ($coroutine:expr, $frag:expr, $arg:expr $(,)?) => {
53 match $crate::coroutine::ImapCoroutine::resume($coroutine, $frag, $arg) {
54 $crate::coroutine::ImapCoroutineState::Yielded(y) => {
55 return $crate::coroutine::ImapCoroutineState::Yielded(y.into());
56 }
57 $crate::coroutine::ImapCoroutineState::Complete(Err(err)) => {
58 return $crate::coroutine::ImapCoroutineState::Complete(Err(err.into()));
59 }
60 $crate::coroutine::ImapCoroutineState::Complete(Ok(value)) => value,
61 }
62 };
63}