io_maildir/maildir/
types.rs1use core::{
4 fmt,
5 hash::{Hash, Hasher},
6 str::FromStr,
7};
8
9use alloc::string::String;
10
11use thiserror::Error;
12
13use crate::path::FsPath;
14
15#[derive(Clone, Debug, Error)]
17pub enum MaildirError {
18 #[error("path {0} is not a directory")]
19 NotDir(FsPath),
20
21 #[error("missing {0}/ subdirectory at Maildir {1}")]
22 MissingSubdir(&'static str, FsPath),
23
24 #[error("invalid Maildir subdir {0:?}: expected cur, new or tmp")]
25 InvalidSubdir(String),
26}
27
28pub const CUR: &str = "cur";
29pub const NEW: &str = "new";
30pub const TMP: &str = "tmp";
31
32#[derive(Clone, Debug, Eq, PartialEq)]
34pub enum MaildirSubdir {
35 Cur,
36 New,
37 Tmp,
38}
39
40impl FromStr for MaildirSubdir {
41 type Err = MaildirError;
42
43 fn from_str(s: &str) -> Result<Self, Self::Err> {
44 match s {
45 CUR => Ok(Self::Cur),
46 NEW => Ok(Self::New),
47 TMP => Ok(Self::Tmp),
48 _ => Err(MaildirError::InvalidSubdir(s.into())),
49 }
50 }
51}
52
53impl fmt::Display for MaildirSubdir {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 match self {
56 Self::Cur => write!(f, "{CUR}"),
57 Self::New => write!(f, "{NEW}"),
58 Self::Tmp => write!(f, "{TMP}"),
59 }
60 }
61}
62
63#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
65pub struct Maildir {
66 root: FsPath,
67}
68
69impl Maildir {
70 pub fn from_path(root: impl Into<FsPath>) -> Self {
72 Self { root: root.into() }
73 }
74
75 pub fn path(&self) -> &FsPath {
76 &self.root
77 }
78
79 pub fn name(&self) -> Option<&str> {
80 self.root.file_name()
81 }
82
83 pub fn subdir(&self, subdir: &MaildirSubdir) -> FsPath {
84 match subdir {
85 MaildirSubdir::Cur => self.cur(),
86 MaildirSubdir::New => self.new(),
87 MaildirSubdir::Tmp => self.tmp(),
88 }
89 }
90
91 pub fn cur(&self) -> FsPath {
92 self.root.join(CUR)
93 }
94
95 pub fn new(&self) -> FsPath {
96 self.root.join(NEW)
97 }
98
99 pub fn tmp(&self) -> FsPath {
100 self.root.join(TMP)
101 }
102}
103
104impl Hash for Maildir {
105 fn hash<H: Hasher>(&self, state: &mut H) {
106 self.root.hash(state);
107 }
108}
109
110impl AsRef<FsPath> for Maildir {
111 fn as_ref(&self) -> &FsPath {
112 &self.root
113 }
114}
115
116impl From<FsPath> for Maildir {
117 fn from(root: FsPath) -> Self {
118 Self { root }
119 }
120}
121
122impl From<String> for Maildir {
123 fn from(root: String) -> Self {
124 Self { root: root.into() }
125 }
126}
127
128impl From<&str> for Maildir {
129 fn from(root: &str) -> Self {
130 Self { root: root.into() }
131 }
132}