io_vdir/collection/
delete.rs1use core::{fmt, mem};
30
31use alloc::collections::BTreeSet;
32
33use thiserror::Error;
34
35use crate::{coroutine::*, path::VdirPath};
36
37#[derive(Clone, Debug, Error)]
39pub enum VdirCollectionDeleteError {
40 #[error("Vdir collection delete failed: unexpected arg {0:?}")]
43 UnexpectedArg(Option<VdirReply>),
44}
45
46#[derive(Clone, Debug, Default, Eq, PartialEq)]
48pub struct VdirCollectionDeleteOptions {}
49
50#[derive(Debug)]
52pub struct VdirCollectionDelete {
53 state: State,
54 #[allow(dead_code)]
55 opts: VdirCollectionDeleteOptions,
56}
57
58impl VdirCollectionDelete {
59 pub fn new(path: impl Into<VdirPath>, opts: VdirCollectionDeleteOptions) -> Self {
62 let paths = BTreeSet::from_iter([path.into()]);
63 Self {
64 opts,
65 state: State::Start { paths },
66 }
67 }
68}
69
70impl VdirCoroutine for VdirCollectionDelete {
71 type Yield = VdirYield;
72 type Return = Result<(), VdirCollectionDeleteError>;
73
74 fn resume(&mut self, arg: Option<VdirReply>) -> VdirCoroutineState<Self::Yield, Self::Return> {
75 match (&mut self.state, arg) {
76 (State::Start { paths }, None) => {
77 let paths = mem::take(paths);
78 self.state = State::Remove;
79 VdirCoroutineState::Yielded(VdirYield::WantsDirRemove(paths))
80 }
81 (State::Remove, Some(VdirReply::DirRemove)) => VdirCoroutineState::Complete(Ok(())),
82 (_, arg) => {
83 let err = VdirCollectionDeleteError::UnexpectedArg(arg);
84 VdirCoroutineState::Complete(Err(err))
85 }
86 }
87 }
88}
89
90#[derive(Debug)]
91enum State {
92 Start { paths: BTreeSet<VdirPath> },
93 Remove,
94}
95
96impl fmt::Display for State {
97 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
98 match self {
99 Self::Start { .. } => f.write_str("start"),
100 Self::Remove => f.write_str("remove collection"),
101 }
102 }
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn removes_collection_directory() {
111 let mut cor =
112 VdirCollectionDelete::new("root/contacts", VdirCollectionDeleteOptions::default());
113
114 let paths = match cor.resume(None) {
115 VdirCoroutineState::Yielded(VdirYield::WantsDirRemove(paths)) => paths,
116 state => panic!("expected WantsDirRemove, got {state:?}"),
117 };
118 assert!(paths.contains(&VdirPath::from("root/contacts")));
119
120 match cor.resume(Some(VdirReply::DirRemove)) {
121 VdirCoroutineState::Complete(Ok(())) => {}
122 state => panic!("expected Complete(Ok), got {state:?}"),
123 }
124 }
125
126 #[test]
127 fn unexpected_reply_returns_error() {
128 let mut cor =
129 VdirCollectionDelete::new("root/contacts", VdirCollectionDeleteOptions::default());
130 let _ = cor.resume(None);
131
132 let err = match cor.resume(Some(VdirReply::FileRemove)) {
133 VdirCoroutineState::Complete(Err(err)) => err,
134 state => panic!("expected Complete(Err), got {state:?}"),
135 };
136 assert!(matches!(err, VdirCollectionDeleteError::UnexpectedArg(_)));
137 }
138}