1use crate::elements::{
2 Document, Element, Embed, Field, Flag, Section, SectionElement, SectionImpl,
3};
4use crate::queries::{
5 EmbedQuery, EmbedQueryImpl, EmbedQueryParent, FieldQuery, FieldQueryImpl, FieldQueryParent,
6 FlagQuery, FlagQueryImpl, FlagQueryParent,
7};
8use crate::{Error, Printer};
9
10pub enum Matches<'a, T> {
11 Multiple(&'a T, &'a T),
12 One(&'a T),
13 None,
14 WrongType(&'a dyn SectionElement),
15}
16
17pub trait SectionElements {
18 fn single_embed_with_key(&self, key: &str) -> Matches<Embed>;
19 fn single_field_with_key(&self, key: &str) -> Matches<Field>;
20 fn single_flag_with_key(&self, key: &str) -> Matches<Flag>;
21 fn single_section_with_key(&self, key: &str) -> Matches<Section>;
22 fn untouched(&self) -> Vec<&dyn Element>;
23}
24
25pub struct SectionQuery<'a> {
38 element_option: Option<&'a Section>,
39 key: Option<String>,
40 parent: SectionQueryParent<'a>,
41}
42
43pub trait SectionQueryImpl<'a> {
44 fn element(&self) -> Option<&Section>;
45 #[allow(clippy::new_ret_no_self)]
46 fn new(
47 element_option: Option<&'a Section>,
48 key: Option<String>,
49 parent: SectionQueryParent<'a>,
50 ) -> SectionQuery<'a>;
51}
52
53pub enum SectionQueryParent<'a> {
54 Document(&'a Document),
55 Section(&'a Section),
56 SectionQuery(&'a SectionQuery<'a>),
57}
58
59impl SectionElements for Vec<Box<dyn SectionElement>> {
60 fn single_embed_with_key(&self, key: &str) -> Matches<Embed> {
61 let mut embed_option: Option<&Embed> = None;
62
63 for element in self.iter().filter(|element| element.key() == key) {
64 match element.as_embed() {
65 Some(embed) => match embed_option {
66 Some(prev_embed) => return Matches::Multiple(prev_embed, embed),
67 None => embed_option = Some(embed),
68 },
69 None => return Matches::WrongType(element.as_ref()),
70 }
71 }
72
73 match embed_option {
74 Some(embed) => {
75 embed.touch();
76 Matches::One(embed)
77 }
78 None => Matches::None,
79 }
80 }
81
82 fn single_field_with_key(&self, key: &str) -> Matches<Field> {
83 let mut field_option: Option<&Field> = None;
84
85 for element in self.iter().filter(|element| element.key() == key) {
86 match element.as_field() {
87 Some(field) => match field_option {
88 Some(prev_field) => return Matches::Multiple(prev_field, field),
89 None => field_option = Some(field),
90 },
91 None => return Matches::WrongType(element.as_ref()),
92 }
93 }
94
95 match field_option {
96 Some(field) => {
97 field.touch();
98 Matches::One(field)
99 }
100 None => Matches::None,
101 }
102 }
103
104 fn single_flag_with_key(&self, key: &str) -> Matches<Flag> {
105 let mut flag_option: Option<&Flag> = None;
106
107 for element in self.iter().filter(|element| element.key() == key) {
108 match element.as_flag() {
109 Some(flag) => match flag_option {
110 Some(prev_flag) => return Matches::Multiple(prev_flag, flag),
111 None => flag_option = Some(flag),
112 },
113 None => return Matches::WrongType(element.as_ref()),
114 }
115 }
116
117 match flag_option {
118 Some(flag) => {
119 flag.touch();
120 Matches::One(flag)
121 }
122 None => Matches::None,
123 }
124 }
125
126 fn single_section_with_key(&self, key: &str) -> Matches<Section> {
127 let mut section_option: Option<&Section> = None;
128
129 for element in self.iter().filter(|element| element.key() == key) {
130 match element.as_section() {
131 Some(section) => match section_option {
132 Some(prev_section) => return Matches::Multiple(prev_section, section),
133 None => section_option = Some(section),
134 },
135 None => return Matches::WrongType(element.as_ref()),
136 }
137 }
138
139 match section_option {
140 Some(section) => {
141 section.touch();
142 Matches::One(section)
143 }
144 None => Matches::None,
145 }
146 }
147
148 fn untouched(&self) -> Vec<&dyn Element> {
149 let mut result = Vec::new();
150
151 for element in self {
152 if !element.touched() {
153 result.push(element.as_element());
154 } else if let Some(field) = element.as_field() {
155 result.append(&mut field.untouched_elements());
156 } else if let Some(section) = element.as_section() {
157 result.append(&mut section.untouched_elements());
158 }
159 }
160
161 result
162 }
163}
164
165impl<'a> SectionQuery<'a> {
166 pub fn elements(&self) -> &[Box<dyn SectionElement>] {
167 match self.element_option {
168 Some(section) => section.get_elements(),
169 None => &[],
170 }
171 }
172
173 pub fn embed(&self, key: &str) -> Result<EmbedQuery, Error> {
174 let element_option = match self.element_option {
175 Some(section) => match section.get_elements_ref().single_embed_with_key(key) {
176 Matches::None => None,
177 Matches::One(embed) => Some(embed),
178 Matches::Multiple(_first, second) => {
179 return Err(Error::new(
180 "Only a single embed was expected".to_string(),
181 second.line_number,
182 ))
183 }
184 Matches::WrongType(element) => {
185 return Err(Error::new(
186 "An embed was expected".to_string(),
187 element.line_number(),
188 ))
189 }
190 },
191 None => None,
192 };
193
194 Ok(EmbedQuery::new(
195 element_option,
196 Some(key.to_string()),
197 EmbedQueryParent::SectionQuery(self),
198 ))
199 }
200
201 pub fn field(&self, key: &str) -> Result<FieldQuery, Error> {
202 let element_option = match self.element_option {
203 Some(section) => match section.get_elements_ref().single_field_with_key(key) {
204 Matches::None => None,
205 Matches::One(field) => Some(field),
206 Matches::Multiple(_first, second) => {
207 return Err(Error::new(
208 "Only a single field was expected".to_string(),
209 second.line_number,
210 ))
211 }
212 Matches::WrongType(element) => {
213 return Err(Error::new(
214 "A field was expected".to_string(),
215 element.line_number(),
216 ))
217 }
218 },
219 None => None,
220 };
221
222 Ok(FieldQuery::new(
223 element_option,
224 Some(key.to_string()),
225 FieldQueryParent::SectionQuery(self),
226 ))
227 }
228
229 pub fn flag(&self, key: &str) -> Result<FlagQuery, Error> {
230 let element_option = match self.element_option {
231 Some(section) => match section.get_elements_ref().single_flag_with_key(key) {
232 Matches::None => None,
233 Matches::One(flag) => Some(flag),
234 Matches::Multiple(_first, second) => {
235 return Err(Error::new(
236 "Only a single flag was expected".to_string(),
237 second.line_number,
238 ))
239 }
240 Matches::WrongType(element) => {
241 return Err(Error::new(
242 "A flag was expected".to_string(),
243 element.line_number(),
244 ))
245 }
246 },
247 None => None,
248 };
249
250 Ok(FlagQuery::new(
251 element_option,
252 Some(key.to_string()),
253 FlagQueryParent::SectionQuery(self),
254 ))
255 }
256
257 pub fn missing_error(&self) -> Error {
258 match self.parent {
259 SectionQueryParent::Document(_) => Error::new(
260 format!(
261 "Section {} not found",
262 self.key.as_deref().unwrap_or("(can have any key)")
263 ),
264 Document::LINE_NUMBER,
265 ),
266 SectionQueryParent::Section(section) => Error::new(
267 format!(
268 "Section {} not found",
269 self.key.as_deref().unwrap_or("(can have any key)")
270 ),
271 section.line_number,
272 ),
273 SectionQueryParent::SectionQuery(section_query) => match section_query.element_option {
274 Some(section) => Error::new(
275 format!(
276 "Section {} not found",
277 self.key.as_deref().unwrap_or("(can have any key)")
278 ),
279 section.line_number,
280 ),
281 None => section_query.missing_error(),
282 },
283 }
284 }
285
286 pub fn section(&self, key: &str) -> Result<SectionQuery, Error> {
287 let element_option = match self.element_option {
288 Some(section) => match section.get_elements_ref().single_section_with_key(key) {
289 Matches::None => None,
290 Matches::One(subsection) => Some(subsection),
291 Matches::Multiple(_first, second) => {
292 return Err(Error::new(
293 "Only a single section was expected".to_string(),
294 second.line_number,
295 ))
296 }
297 Matches::WrongType(element) => {
298 return Err(Error::new(
299 "A section was expected".to_string(),
300 element.line_number(),
301 ))
302 }
303 },
304 None => None,
305 };
306
307 Ok(SectionQuery::new(
308 element_option,
309 Some(key.to_string()),
310 SectionQueryParent::SectionQuery(self),
311 ))
312 }
313
314 pub fn snippet(&self) -> Result<String, Error> {
315 match self.element_option {
316 Some(section) => Ok(section.snippet()),
317 None => Err(self.missing_error()),
318 }
319 }
320
321 pub fn snippet_with_options(
322 &self,
323 printer: &dyn Printer,
324 gutter: bool,
325 ) -> Result<String, Error> {
326 match self.element_option {
327 Some(section) => Ok(section.snippet_with_options(printer, gutter)),
328 None => Err(self.missing_error()),
329 }
330 }
331}
332
333impl<'a> SectionQueryImpl<'a> for SectionQuery<'a> {
334 fn element(&self) -> Option<&Section> {
335 self.element_option
336 }
337
338 fn new(
339 element_option: Option<&'a Section>,
340 key: Option<String>,
341 parent: SectionQueryParent<'a>,
342 ) -> SectionQuery<'a> {
343 SectionQuery {
344 element_option,
345 key,
346 parent,
347 }
348 }
349}