io_email/message/m2dir/
add.rs1use alloc::{string::String, vec::Vec};
19use core::mem;
20use std::path::PathBuf;
21
22use io_m2dir::{
23 coroutine::*,
24 entry::store::{
25 M2dirEntryStore as InnerStore, M2dirEntryStoreError as StoreErr,
26 M2dirEntryStoreOptions as StoreOpts,
27 },
28 flag::{
29 set::{
30 M2dirFlagSet as InnerFlagSet, M2dirFlagSetError as FlagSetErr,
31 M2dirFlagSetOptions as FlagSetOpts,
32 },
33 types::M2dirFlags,
34 },
35 m2dir::types::M2dir,
36};
37use log::trace;
38use thiserror::Error;
39
40use crate::{
41 flag::types::Flag,
42 m2dir::convert::{InvalidMailboxName, flags_to_m2dir, resolve_mailbox},
43};
44
45#[derive(Debug, Error)]
47pub enum M2dirMessageAddError {
48 #[error(transparent)]
49 Store(#[from] StoreErr),
50 #[error(transparent)]
51 SetFlags(#[from] FlagSetErr),
52 #[error(transparent)]
53 InvalidMailbox(#[from] InvalidMailboxName),
54}
55
56pub struct M2dirMessageAdd {
58 state: State,
59 m2dir: M2dir,
60 flags: M2dirFlags,
61}
62
63impl M2dirMessageAdd {
64 pub fn new(
65 root: impl Into<PathBuf>,
66 mailbox: &str,
67 flags: &[Flag],
68 bytes: Vec<u8>,
69 ) -> Result<Self, M2dirMessageAddError> {
70 trace!("prepare m2dir message add");
71 let m2dir = resolve_mailbox(root, mailbox)?;
72 let store = InnerStore::new(m2dir.clone(), bytes, StoreOpts::default());
73 Ok(Self {
74 state: State::Storing(store),
75 m2dir,
76 flags: flags_to_m2dir(flags),
77 })
78 }
79}
80
81enum State {
82 Storing(InnerStore),
83 SettingFlags { set: InnerFlagSet, id: String },
84 Done,
85}
86
87impl M2dirCoroutine for M2dirMessageAdd {
88 type Yield = M2dirYield;
89 type Return = Result<String, M2dirMessageAddError>;
90
91 fn resume(&mut self, arg: Option<M2dirArg>) -> M2dirCoroutineState<Self::Yield, Self::Return> {
92 match mem::replace(&mut self.state, State::Done) {
93 State::Storing(mut store) => match store.resume(arg) {
94 M2dirCoroutineState::Yielded(y) => {
95 self.state = State::Storing(store);
96 M2dirCoroutineState::Yielded(y)
97 }
98 M2dirCoroutineState::Complete(Ok(entry)) => {
99 if self.flags.is_empty() {
100 M2dirCoroutineState::Complete(Ok(entry.id().into()))
101 } else {
102 let id: String = entry.id().into();
103 let set = InnerFlagSet::new(
104 &self.m2dir,
105 &id,
106 self.flags.clone(),
107 FlagSetOpts::default(),
108 );
109 self.state = State::SettingFlags { set, id };
110 M2dirCoroutine::resume(self, None)
111 }
112 }
113 M2dirCoroutineState::Complete(Err(err)) => {
114 M2dirCoroutineState::Complete(Err(err.into()))
115 }
116 },
117 State::SettingFlags { mut set, id } => match set.resume(arg) {
118 M2dirCoroutineState::Yielded(y) => {
119 self.state = State::SettingFlags { set, id };
120 M2dirCoroutineState::Yielded(y)
121 }
122 M2dirCoroutineState::Complete(Ok(())) => M2dirCoroutineState::Complete(Ok(id)),
123 M2dirCoroutineState::Complete(Err(err)) => {
124 M2dirCoroutineState::Complete(Err(err.into()))
125 }
126 },
127 State::Done => unreachable!("M2dirMessageAdd resumed after completion"),
128 }
129 }
130}