imap_client/tasks/
resolver.rs

1use imap_next::{
2    client::Client as ClientNext,
3    imap_types::response::{Response, Status},
4    Interrupt, State,
5};
6use tracing::{debug, warn};
7
8use super::{Scheduler, SchedulerError, SchedulerEvent, Task, TaskHandle};
9
10/// The resolver is a scheduler than manages one task at a time.
11pub struct Resolver {
12    pub scheduler: Scheduler,
13}
14
15impl Resolver {
16    /// Create a new resolver.
17    pub fn new(client_next: ClientNext) -> Self {
18        Self {
19            scheduler: Scheduler::new(client_next),
20        }
21    }
22
23    /// Enqueue a [`Task`] for immediate resolution.
24    pub fn resolve<T: Task>(&mut self, task: T) -> ResolvingTask<T> {
25        let handle = self.scheduler.enqueue_task(task);
26
27        ResolvingTask {
28            resolver: self,
29            handle,
30        }
31    }
32}
33
34impl State for Resolver {
35    type Event = SchedulerEvent;
36    type Error = SchedulerError;
37
38    fn enqueue_input(&mut self, bytes: &[u8]) {
39        self.scheduler.enqueue_input(bytes);
40    }
41
42    fn next(&mut self) -> Result<Self::Event, Interrupt<Self::Error>> {
43        self.scheduler.progress()
44    }
45}
46
47pub struct ResolvingTask<'a, T: Task> {
48    resolver: &'a mut Resolver,
49    handle: TaskHandle<T>,
50}
51
52impl<T: Task> State for ResolvingTask<'_, T> {
53    type Event = T::Output;
54    type Error = SchedulerError;
55
56    fn enqueue_input(&mut self, bytes: &[u8]) {
57        self.resolver.enqueue_input(bytes);
58    }
59
60    fn next(&mut self) -> Result<Self::Event, Interrupt<Self::Error>> {
61        loop {
62            match self.resolver.next()? {
63                SchedulerEvent::GreetingReceived(greeting) => {
64                    debug!("received greeting: {greeting:?}");
65                }
66                SchedulerEvent::TaskFinished(mut token) => {
67                    if let Some(output) = self.handle.resolve(&mut token) {
68                        break Ok(output);
69                    } else {
70                        warn!(?token, "received unexpected task token")
71                    }
72                }
73                SchedulerEvent::Unsolicited(unsolicited) => {
74                    if let Response::Status(Status::Bye(bye)) = unsolicited {
75                        let err = SchedulerError::UnexpectedByeResponse(bye);
76                        break Err(Interrupt::Error(err));
77                    } else {
78                        warn!(?unsolicited, "received unsolicited");
79                    }
80                }
81            }
82        }
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use static_assertions::assert_impl_all;
89
90    use super::Resolver;
91
92    assert_impl_all!(Resolver: Send);
93}