Skip to main content

io_gmail/
coroutine.rs

1//! Coroutine contract shared by every Gmail exchange.
2//!
3//! Defines the `GmailCoroutine` trait, its `GmailYield` and
4//! `GmailCoroutineState` companions, and the `gmail_try!` macro (the
5//! coroutine equivalent of `?`).
6
7use alloc::vec::Vec;
8
9/// Progress of a coroutine after a resume: either an I/O request the
10/// caller must fulfill, or the terminal value.
11#[derive(Debug)]
12pub enum GmailCoroutineState<Y, R> {
13    /// The coroutine needs I/O before it can go further.
14    Yielded(Y),
15    /// The coroutine finished with its terminal value.
16    Complete(R),
17}
18
19/// A resumable, I/O-free Gmail operation.
20pub trait GmailCoroutine {
21    /// The I/O request type yielded while the exchange is in progress.
22    type Yield;
23    /// The terminal value type produced when the exchange completes.
24    type Return;
25
26    /// Advances the coroutine with the bytes read since the last yield
27    /// (`None` when there is nothing to feed).
28    fn resume(&mut self, arg: Option<&[u8]>) -> GmailCoroutineState<Self::Yield, Self::Return>;
29}
30
31/// The I/O request a coroutine yields: read bytes from the stream, or
32/// write the given bytes to it.
33#[derive(Debug)]
34pub enum GmailYield {
35    /// The coroutine wants bytes read from the stream.
36    WantsRead,
37    /// The coroutine wants the given bytes written to the stream.
38    WantsWrite(Vec<u8>),
39}
40
41/// Resumes an inner coroutine, forwarding its yields and
42/// short-circuiting its errors: the coroutine equivalent of `?`.
43#[macro_export]
44macro_rules! gmail_try {
45    ($coroutine:expr, $arg:expr $(,)?) => {
46        match $crate::coroutine::GmailCoroutine::resume($coroutine, $arg) {
47            $crate::coroutine::GmailCoroutineState::Yielded(y) => {
48                return $crate::coroutine::GmailCoroutineState::Yielded(y.into());
49            }
50            $crate::coroutine::GmailCoroutineState::Complete(Err(err)) => {
51                log::trace!("error during coroutine execution: {err}");
52                return $crate::coroutine::GmailCoroutineState::Complete(Err(err.into()));
53            }
54            $crate::coroutine::GmailCoroutineState::Complete(Ok(value)) => value,
55        }
56    };
57}