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::AwaitRemove;
79 VdirCoroutineState::Yielded(VdirYield::WantsDirRemove(paths))
80 }
81 (State::AwaitRemove, Some(VdirReply::DirRemove)) => {
82 VdirCoroutineState::Complete(Ok(()))
83 }
84 (_, arg) => {
85 let err = VdirCollectionDeleteError::UnexpectedArg(arg);
86 VdirCoroutineState::Complete(Err(err))
87 }
88 }
89 }
90}
91
92#[derive(Debug)]
93enum State {
94 Start { paths: BTreeSet<VdirPath> },
95 AwaitRemove,
96}
97
98impl fmt::Display for State {
99 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
100 match self {
101 Self::Start { .. } => f.write_str("start"),
102 Self::AwaitRemove => f.write_str("await remove reply"),
103 }
104 }
105}
106
107#[cfg(test)]
108mod tests {
109 use super::*;
110
111 #[test]
112 fn removes_collection_directory() {
113 let mut cor =
114 VdirCollectionDelete::new("root/contacts", VdirCollectionDeleteOptions::default());
115
116 let paths = match cor.resume(None) {
117 VdirCoroutineState::Yielded(VdirYield::WantsDirRemove(paths)) => paths,
118 state => panic!("expected WantsDirRemove, got {state:?}"),
119 };
120 assert!(paths.contains(&VdirPath::from("root/contacts")));
121
122 match cor.resume(Some(VdirReply::DirRemove)) {
123 VdirCoroutineState::Complete(Ok(())) => {}
124 state => panic!("expected Complete(Ok), got {state:?}"),
125 }
126 }
127
128 #[test]
129 fn unexpected_reply_returns_error() {
130 let mut cor =
131 VdirCollectionDelete::new("root/contacts", VdirCollectionDeleteOptions::default());
132 let _ = cor.resume(None);
133
134 let err = match cor.resume(Some(VdirReply::FileRemove)) {
135 VdirCoroutineState::Complete(Err(err)) => err,
136 state => panic!("expected Complete(Err), got {state:?}"),
137 };
138 assert!(matches!(err, VdirCollectionDeleteError::UnexpectedArg(_)));
139 }
140}