1use std::fmt::{Display, Formatter};
4
5#[cfg(feature = "arbitrary")]
6use arbitrary::Arbitrary;
7#[cfg(feature = "bounded-static")]
8use bounded_static::ToStatic;
9#[cfg(feature = "serde")]
10use serde::{Deserialize, Serialize};
11
12use crate::{core::Atom, error::ValidationError};
13
14#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
27#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
28#[derive(Debug, Clone, PartialEq, Eq, Hash)]
29pub enum Flag<'a> {
30 Answered,
32 Deleted,
34 Draft,
36 Flagged,
38 Seen,
40 Extension(FlagExtension<'a>),
42 Keyword(Atom<'a>),
44}
45
46#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
50#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
51#[derive(Debug, Clone, PartialEq, Eq, Hash)]
52pub struct FlagExtension<'a>(Atom<'a>);
53
54impl<'a> Flag<'a> {
55 pub fn system(atom: Atom<'a>) -> Self {
56 match atom.as_ref().to_ascii_lowercase().as_ref() {
57 "answered" => Self::Answered,
58 "deleted" => Self::Deleted,
59 "draft" => Self::Draft,
60 "flagged" => Self::Flagged,
61 "seen" => Self::Seen,
62 _ => Self::Extension(FlagExtension(atom)),
63 }
64 }
65
66 pub fn keyword(atom: Atom<'a>) -> Self {
67 Self::Keyword(atom)
68 }
69}
70
71impl<'a> TryFrom<&'a str> for Flag<'a> {
72 type Error = ValidationError;
73
74 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
75 Ok(if let Some(value) = value.strip_prefix('\\') {
76 Self::system(Atom::try_from(value)?)
77 } else {
78 Self::keyword(Atom::try_from(value)?)
79 })
80 }
81}
82
83impl<'a> Display for Flag<'a> {
84 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
85 match self {
86 Flag::Answered => f.write_str("\\Answered"),
87 Flag::Deleted => f.write_str("\\Deleted"),
88 Flag::Draft => f.write_str("\\Draft"),
89 Flag::Flagged => f.write_str("\\Flagged"),
90 Flag::Seen => f.write_str("\\Seen"),
91 Flag::Extension(other) => write!(f, "\\{}", other.0),
92 Flag::Keyword(atom) => write!(f, "{}", atom),
93 }
94 }
95}
96
97#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
98#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
99#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
100#[derive(Debug, Clone, PartialEq, Eq, Hash)]
101pub enum FlagFetch<'a> {
102 Flag(Flag<'a>),
103
104 Recent,
111}
112
113#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
114#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
115#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
116#[derive(Debug, Clone, PartialEq, Eq, Hash)]
117pub enum FlagPerm<'a> {
118 Flag(Flag<'a>),
119
120 Asterisk,
123}
124
125#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
127#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
128#[derive(Debug, Clone, PartialEq, Eq, Hash)]
129pub enum FlagNameAttribute<'a> {
130 Noinferiors,
134
135 Noselect,
137
138 Marked,
142
143 Unmarked,
146
147 Extension(FlagNameAttributeExtension<'a>),
149}
150
151#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
153#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
154#[derive(Debug, Clone, PartialEq, Eq, Hash)]
155pub struct FlagNameAttributeExtension<'a>(Atom<'a>);
156
157impl<'a> FlagNameAttribute<'a> {
158 pub fn is_selectability(&self) -> bool {
159 matches!(
160 self,
161 FlagNameAttribute::Noselect | FlagNameAttribute::Marked | FlagNameAttribute::Unmarked
162 )
163 }
164}
165
166impl<'a> From<Atom<'a>> for FlagNameAttribute<'a> {
167 fn from(atom: Atom<'a>) -> Self {
168 match atom.as_ref().to_ascii_lowercase().as_ref() {
169 "noinferiors" => Self::Noinferiors,
170 "noselect" => Self::Noselect,
171 "marked" => Self::Marked,
172 "unmarked" => Self::Unmarked,
173 _ => Self::Extension(FlagNameAttributeExtension(atom)),
174 }
175 }
176}
177
178impl<'a> Display for FlagNameAttribute<'a> {
179 fn fmt(&self, f: &mut Formatter) -> std::fmt::Result {
180 match self {
181 Self::Noinferiors => f.write_str("\\Noinferiors"),
182 Self::Noselect => f.write_str("\\Noselect"),
183 Self::Marked => f.write_str("\\Marked"),
184 Self::Unmarked => f.write_str("\\Unmarked"),
185 Self::Extension(extension) => write!(f, "\\{}", extension.0),
186 }
187 }
188}
189
190#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
191#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
192#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
193#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
194pub enum StoreType {
195 Replace,
196 Add,
197 Remove,
198}
199
200#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
201#[cfg_attr(feature = "bounded-static", derive(ToStatic))]
202#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
203#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
204pub enum StoreResponse {
205 Answer,
206 Silent,
207}