io_email/message/maildir/
move.rs1use alloc::{collections::VecDeque, string::String};
13
14use io_maildir::{
15 coroutine::*,
16 entry::r#move::{MaildirEntryMove as InnerMove, MaildirEntryMoveError as InnerErr},
17 maildir::types::Maildir,
18 store::MaildirStore,
19};
20use log::trace;
21use thiserror::Error;
22
23use crate::maildir::convert::{InvalidMailboxName, mailbox_path};
24
25#[derive(Debug, Error)]
27pub enum MaildirMessageMoveError {
28 #[error(transparent)]
29 Move(#[from] InnerErr),
30 #[error(transparent)]
31 InvalidMailbox(#[from] InvalidMailboxName),
32}
33
34pub struct MaildirMessageMove {
36 source: Maildir,
37 target: Maildir,
38 pending: VecDeque<String>,
39 current: Option<InnerMove>,
40}
41
42impl MaildirMessageMove {
43 pub fn new(
44 store: &MaildirStore,
45 from: &str,
46 to: &str,
47 ids: &[&str],
48 ) -> Result<Self, MaildirMessageMoveError> {
49 trace!("prepare Maildir message move");
50 let source = Maildir::from_path(store.resolve(&mailbox_path(from)?));
51 let target = Maildir::from_path(store.resolve(&mailbox_path(to)?));
52 Ok(Self {
53 source,
54 target,
55 pending: ids.iter().map(|s| (*s).into()).collect(),
56 current: None,
57 })
58 }
59}
60
61impl MaildirCoroutine for MaildirMessageMove {
62 type Yield = MaildirYield;
63 type Return = Result<(), MaildirMessageMoveError>;
64
65 fn resume(
66 &mut self,
67 arg: Option<MaildirReply>,
68 ) -> MaildirCoroutineState<Self::Yield, Self::Return> {
69 let mut arg = arg;
70 loop {
71 if self.current.is_none() {
72 let Some(id) = self.pending.pop_front() else {
73 return MaildirCoroutineState::Complete(Ok(()));
74 };
75 self.current = Some(InnerMove::new(
76 id,
77 self.source.clone(),
78 self.target.clone(),
79 None,
80 ));
81 }
82
83 let inner = self.current.as_mut().unwrap();
84 match inner.resume(arg.take()) {
85 MaildirCoroutineState::Complete(Ok(())) => {
86 self.current = None;
87 }
88 MaildirCoroutineState::Yielded(y) => return MaildirCoroutineState::Yielded(y),
89 MaildirCoroutineState::Complete(Err(err)) => {
90 return MaildirCoroutineState::Complete(Err(err.into()));
91 }
92 }
93 }
94 }
95}