sieve/compiler/grammar/tests/
test_mailbox.rs1use crate::{
8 Metadata,
9 compiler::{
10 CompileError, RawValue, Value,
11 grammar::{
12 Capability, Comparator,
13 instruction::{CompilerState, MapLocalVars},
14 },
15 lexer::{Token, word::Word},
16 },
17};
18
19use crate::compiler::grammar::{MatchType, test::Test};
20
21#[derive(Debug, Clone, PartialEq, Eq)]
22#[cfg_attr(
23 any(test, feature = "serde"),
24 derive(serde::Serialize, serde::Deserialize)
25)]
26#[cfg_attr(
27 feature = "rkyv",
28 derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
29)]
30pub(crate) struct TestMailboxExists {
31 pub mailbox_names: Box<[Value]>,
32 pub is_not: bool,
33}
34
35#[derive(Debug, Clone, PartialEq, Eq)]
36#[cfg_attr(
37 any(test, feature = "serde"),
38 derive(serde::Serialize, serde::Deserialize)
39)]
40#[cfg_attr(
41 feature = "rkyv",
42 derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
43)]
44pub(crate) struct TestMetadataExists {
45 pub mailbox: Option<Value>,
46 pub annotation_names: Box<[Value]>,
47 pub is_not: bool,
48}
49
50#[derive(Debug, Clone, PartialEq, Eq)]
59#[cfg_attr(
60 any(test, feature = "serde"),
61 derive(serde::Serialize, serde::Deserialize)
62)]
63#[cfg_attr(
64 feature = "rkyv",
65 derive(rkyv::Serialize, rkyv::Deserialize, rkyv::Archive)
66)]
67pub(crate) struct TestMetadata {
68 pub match_type: MatchType,
69 pub comparator: Comparator,
70 pub medatata: Metadata<Value>,
71 pub key_list: Box<[Value]>,
72 pub is_not: bool,
73}
74
75impl CompilerState<'_> {
83 pub(crate) fn parse_test_mailboxexists(&mut self) -> Result<Test, CompileError> {
84 Ok(Test::MailboxExists(Box::new(TestMailboxExists {
85 mailbox_names: self.parse_strings(false)?.into(),
86 is_not: false,
87 })))
88 }
89
90 pub(crate) fn parse_test_metadataexists(&mut self) -> Result<Test, CompileError> {
91 Ok(Test::MetadataExists(Box::new(TestMetadataExists {
92 mailbox: self.parse_string()?.into(),
93 annotation_names: self.parse_strings(false)?.into(),
94 is_not: false,
95 })))
96 }
97
98 pub(crate) fn parse_test_servermetadataexists(&mut self) -> Result<Test, CompileError> {
99 Ok(Test::MetadataExists(Box::new(TestMetadataExists {
100 mailbox: None,
101 annotation_names: self.parse_strings(false)?.into(),
102 is_not: false,
103 })))
104 }
105
106 pub(crate) fn parse_test_metadata(&mut self) -> Result<Test, CompileError> {
107 let mut match_type = MatchType::Is;
108 let mut comparator = Comparator::AsciiCaseMap;
109 let mut mailbox = None;
110 let mut annotation_name = None;
111 let key_list: Vec<RawValue>;
112
113 loop {
114 let token_info = self.tokens.unwrap_next()?;
115 match token_info.token {
116 Token::Tag(
117 word @ (Word::Is
118 | Word::Contains
119 | Word::Matches
120 | Word::Value
121 | Word::Count
122 | Word::Regex),
123 ) => {
124 self.validate_argument(
125 1,
126 match word {
127 Word::Value | Word::Count => Capability::Relational.into(),
128 Word::Regex => Capability::Regex.into(),
129 Word::List => Capability::ExtLists.into(),
130 _ => None,
131 },
132 token_info.line_num,
133 token_info.line_pos,
134 )?;
135
136 match_type = self.parse_match_type(word)?;
137 }
138 Token::Tag(Word::Comparator) => {
139 self.validate_argument(2, None, token_info.line_num, token_info.line_pos)?;
140 comparator = self.parse_comparator()?;
141 }
142 _ => {
143 if mailbox.is_none() {
144 mailbox = self.parse_string_token(token_info)?.into();
145 } else if annotation_name.is_none() {
146 annotation_name = self.parse_string_token(token_info)?.into();
147 } else {
148 key_list = self.parse_raw_strings_token(token_info)?;
149 break;
150 }
151 }
152 }
153 }
154 let key_list = self.validate_match(&match_type, &comparator, key_list)?;
155
156 Ok(Test::Metadata(Box::new(TestMetadata {
157 match_type,
158 comparator,
159 medatata: Metadata::Mailbox {
160 name: mailbox.unwrap(),
161 annotation: annotation_name.unwrap(),
162 },
163 key_list: key_list.into(),
164 is_not: false,
165 })))
166 }
167
168 pub(crate) fn parse_test_servermetadata(&mut self) -> Result<Test, CompileError> {
169 let mut match_type = MatchType::Is;
170 let mut comparator = Comparator::AsciiCaseMap;
171 let mut annotation_name = None;
172 let key_list: Vec<RawValue>;
173
174 loop {
175 let token_info = self.tokens.unwrap_next()?;
176 match token_info.token {
177 Token::Tag(
178 word @ (Word::Is
179 | Word::Contains
180 | Word::Matches
181 | Word::Value
182 | Word::Count
183 | Word::Regex),
184 ) => {
185 self.validate_argument(
186 1,
187 match word {
188 Word::Value | Word::Count => Capability::Relational.into(),
189 Word::Regex => Capability::Regex.into(),
190 Word::List => Capability::ExtLists.into(),
191 _ => None,
192 },
193 token_info.line_num,
194 token_info.line_pos,
195 )?;
196
197 match_type = self.parse_match_type(word)?;
198 }
199 Token::Tag(Word::Comparator) => {
200 self.validate_argument(2, None, token_info.line_num, token_info.line_pos)?;
201 comparator = self.parse_comparator()?;
202 }
203 _ => {
204 if annotation_name.is_none() {
205 annotation_name = self.parse_string_token(token_info)?.into();
206 } else {
207 key_list = self.parse_raw_strings_token(token_info)?;
208 break;
209 }
210 }
211 }
212 }
213 let key_list = self.validate_match(&match_type, &comparator, key_list)?;
214
215 Ok(Test::Metadata(Box::new(TestMetadata {
216 match_type,
217 comparator,
218 medatata: Metadata::Server {
219 annotation: annotation_name.unwrap(),
220 },
221 key_list: key_list.into(),
222 is_not: false,
223 })))
224 }
225}
226
227impl MapLocalVars for Metadata<Value> {
228 fn map_local_vars(&mut self, last_id: u16) {
229 match self {
230 Metadata::Mailbox { name, annotation } => {
231 name.map_local_vars(last_id);
232 annotation.map_local_vars(last_id);
233 }
234 Metadata::Server { annotation } => {
235 annotation.map_local_vars(last_id);
236 }
237 }
238 }
239}