1use std::cell::Cell;
2use std::ops::{Range, RangeInclusive};
3use std::rc::Rc;
4use std::str::FromStr;
5
6use crate::elements::{AttributeImpl, CommentImpl, DocumentInternals, ElementImpl, ItemImpl};
7use crate::{Attribute, Element, Error, Item, Printer, SectionElement};
8
9#[derive(Debug)]
10pub struct Field {
11 content: FieldContent,
12 document_internals: Rc<DocumentInternals>,
13 escape_operator_ranges: Option<(Range<usize>, Range<usize>)>,
14 key_range: Range<usize>,
15 line_begin_index: usize,
16 pub line_number: u32,
17 operator_index: usize,
18 touched: Cell<bool>,
19}
20
21#[derive(Debug)]
22pub enum FieldContent {
23 Attributes(Vec<Attribute>),
24 Items(Vec<Item>),
25 None,
26 Value(Range<usize>),
27}
28
29pub trait FieldImpl {
30 fn get_content(&self) -> &FieldContent;
31 fn get_content_mut(&mut self) -> &mut FieldContent;
32 fn get_document_content(&self) -> &str;
33 #[allow(clippy::new_ret_no_self)]
34 fn new(
35 content: FieldContent,
36 document_internals: Rc<DocumentInternals>,
37 escape_operator_ranges: Option<(Range<usize>, Range<usize>)>,
38 key_range: Range<usize>,
39 line_begin_index: usize,
40 line_number: u32,
41 operator_index: usize,
42 ) -> Field;
43 fn set_content(&mut self, content: FieldContent);
44}
45
46impl Field {
47 pub fn attributes(&self) -> Result<&[Attribute], Error> {
48 match &self.content {
49 FieldContent::Attributes(attributes) => {
50 for attribute in attributes.iter() {
51 attribute.touch();
52 }
53 Ok(attributes.as_slice())
54 }
55 FieldContent::Items(_) => Err(Error::new(
56 "Attributes expected, Items found".to_string(),
57 self.line_number,
58 )),
59 FieldContent::Value { .. } => Err(Error::new(
60 "Attributes expected, Value found".to_string(),
61 self.line_number,
62 )),
63 FieldContent::None => Ok(&[]),
64 }
65 }
66
67 pub fn items(&self) -> Result<&[Item], Error> {
68 match &self.content {
69 FieldContent::Attributes(_) => Err(Error::new(
70 "Items expected, Attributes found".to_string(),
71 self.line_number,
72 )),
73 FieldContent::Items(items) => {
74 for item in items.iter() {
75 item.touch();
76 }
77 Ok(items.as_slice())
78 }
79 FieldContent::Value { .. } => Err(Error::new(
80 "Items expected, Value found".to_string(),
81 self.line_number,
82 )),
83 FieldContent::None => Ok(&[]),
84 }
85 }
86
87 pub fn optional_value(&self) -> Result<Option<String>, Error> {
88 match &self.content {
89 FieldContent::Attributes(attributes) => Err(Error::new(
90 "Value expected, Attributes found".to_string(),
91 attributes[0].line_number,
92 )),
93 FieldContent::Items(items) => Err(Error::new(
94 "Value expected, Items found".to_string(),
95 items[0].line_number,
96 )),
97 FieldContent::Value(range) => Ok(Some(
98 self.document_internals.content[range.clone()].to_owned(),
99 )),
100 FieldContent::None => Ok(None),
101 }
102 }
103
104 pub fn required_attribute(&self, key: &str) -> Result<&Attribute, Error> {
105 match &self.content {
106 FieldContent::Attributes(attributes) => {
107 let mut attribute_option = None;
108
109 for attribute in attributes {
110 if attribute.key() == key {
111 match attribute_option {
112 Some(_) => {
113 return Err(Error::new(
114 format!("Multiple attributes with key {} found", key),
115 self.line_number,
116 ))
117 }
118 None => attribute_option = Some(attribute),
119 }
120 }
121 }
122
123 match attribute_option {
124 Some(attribute) => {
125 attribute.touch();
126 Ok(attribute)
127 }
128 None => Err(Error::new(
129 format!("Missing attribute {}", key),
130 self.line_number,
131 )),
132 }
133 }
134 FieldContent::Items(_) => Err(Error::new(
135 "Attributes expected, Items found".to_string(),
136 self.line_number,
137 )),
138 FieldContent::Value { .. } => Err(Error::new(
139 "Attributes expected, Value found".to_string(),
140 self.line_number,
141 )),
142 FieldContent::None => Err(Error::new(
143 format!("Missing attribute {}", key),
144 self.line_number,
145 )),
146 }
147 }
148
149 pub fn required_value<T: FromStr>(&self) -> Result<T, Error>
150 where
151 <T as FromStr>::Err: std::fmt::Display,
152 {
153 match &self.content {
154 FieldContent::Attributes(_) => Err(Error::new(
155 "Value expected, Attributes found".to_string(),
156 self.line_number,
157 )),
158 FieldContent::Items(_) => Err(Error::new(
159 "Value expected, Items found".to_string(),
160 self.line_number,
161 )),
162 FieldContent::Value(range) => {
163 let value = &self.document_internals.content[range.clone()].to_owned();
164 match value.parse::<T>() {
165 Ok(converted) => Ok(converted),
166 Err(err) => Err(Error::new(format!("{}", err), self.line_number)),
167 }
168 }
169 FieldContent::None => Err(Error::new("Missing value".to_string(), self.line_number)),
170 }
171 }
172
173 pub fn untouched_elements(&self) -> Vec<&dyn Element> {
174 match &self.content {
175 FieldContent::Attributes(attributes) => attributes
176 .iter()
177 .filter(|attribute| !attribute.touched())
178 .map(|attribute| attribute.as_element())
179 .collect(),
180 FieldContent::Items(items) => items
181 .iter()
182 .filter(|item| !item.touched())
183 .map(|item| item.as_element())
184 .collect(),
185 _ => Vec::new(),
186 }
187 }
188}
189
190impl Element for Field {
191 fn as_field(&self) -> Option<&Field> {
192 Some(self)
193 }
194
195 fn is_field(&self) -> bool {
196 true
197 }
198
199 fn line_number(&self) -> u32 {
200 self.line_number
201 }
202
203 fn snippet(&self) -> String {
204 self.snippet_with_options(&*self.document_internals.default_printer, true)
205 }
206
207 fn snippet_with_options(&self, printer: &dyn Printer, gutter: bool) -> String {
208 let mut out = String::new();
209
210 if gutter {
211 out.push_str(&printer.gutter(self.line_number));
212 }
213
214 if let Some((escape_begin_range, escape_end_range)) = &self.escape_operator_ranges {
215 out.push_str(
216 &self.document_internals.content[self.line_begin_index..escape_begin_range.start],
217 );
218 out.push_str(
219 &printer.operator(&self.document_internals.content[escape_begin_range.clone()]),
220 );
221 out.push_str(
222 &self.document_internals.content[escape_begin_range.end..self.key_range.start],
223 );
224 out.push_str(&printer.key(&self.document_internals.content[self.key_range.clone()]));
225 out.push_str(
226 &self.document_internals.content[self.key_range.end..escape_end_range.start],
227 );
228 out.push_str(
229 &printer.operator(&self.document_internals.content[escape_end_range.clone()]),
230 );
231 out.push_str(
232 &self.document_internals.content[escape_end_range.end..self.operator_index],
233 );
234 } else {
235 out.push_str(
236 &self.document_internals.content[self.line_begin_index..self.key_range.start],
237 );
238 out.push_str(&printer.key(&self.document_internals.content[self.key_range.clone()]));
239 out.push_str(&self.document_internals.content[self.key_range.end..self.operator_index]);
240 }
241
242 out.push_str(&self.document_internals.content[self.key_range.end..self.operator_index]);
243 out.push_str(&printer.operator(":"));
244
245 let mut line_number = self.line_number + 1;
246
247 match &self.content {
248 FieldContent::Attributes(attributes) => {
249 for attribute in attributes {
250 out.push('\n');
251
252 let attribute_line_range = attribute.line_range();
253
254 while line_number < *attribute_line_range.start() {
255 if let Some(comment) = self
256 .document_internals
257 .comments
258 .borrow()
259 .iter()
260 .find(|comment| comment.line_number == line_number)
261 {
262 out.push_str(&comment.snippet_with_options(printer, gutter));
263 } else if gutter {
264 out.push_str(&printer.gutter(line_number));
265 }
266
267 out.push('\n');
268
269 line_number += 1;
270 }
271
272 out.push_str(&attribute.snippet_with_options(printer, gutter));
273
274 line_number = *attribute_line_range.end() + 1;
275 }
276 }
277 FieldContent::Items(items) => {
278 for item in items {
279 out.push('\n');
280
281 let item_line_range = item.line_range();
282
283 while line_number < *item_line_range.start() {
284 if let Some(comment) = self
285 .document_internals
286 .comments
287 .borrow()
288 .iter()
289 .find(|comment| comment.line_number == line_number)
290 {
291 out.push_str(&comment.snippet_with_options(printer, gutter));
292 } else if gutter {
293 out.push_str(&printer.gutter(line_number));
294 }
295
296 out.push('\n');
297
298 line_number += 1;
299 }
300
301 out.push_str(&item.snippet_with_options(printer, gutter));
302
303 line_number = *item_line_range.end() + 1;
304 }
305 }
306 FieldContent::Value(value_range) => {
307 out.push_str(
308 &self.document_internals.content[(self.operator_index + 1)..value_range.start],
309 );
310 out.push_str(&printer.value(&self.document_internals.content[value_range.clone()]));
311 }
312 FieldContent::None => (),
313 }
314
315 out
316 }
317
318 fn touch(&self) {
319 self.touched.set(true);
320 }
321}
322
323impl ElementImpl for Field {
324 fn line_range(&self) -> RangeInclusive<u32> {
325 let end = match &self.content {
326 FieldContent::Attributes(attributes) => *attributes.last().unwrap().line_range().end(),
327 FieldContent::Items(items) => *items.last().unwrap().line_range().end(),
328 FieldContent::Value(_) | FieldContent::None => self.line_number,
329 };
330
331 self.line_number..=end
332 }
333
334 fn touched(&self) -> bool {
335 self.touched.get()
336 }
337}
338
339impl FieldImpl for Field {
340 fn get_content(&self) -> &FieldContent {
341 &self.content
342 }
343
344 fn get_content_mut(&mut self) -> &mut FieldContent {
345 &mut self.content
346 }
347
348 fn get_document_content(&self) -> &str {
349 &self.document_internals.content
350 }
351
352 fn new(
353 content: FieldContent,
354 document_internals: Rc<DocumentInternals>,
355 escape_operator_ranges: Option<(Range<usize>, Range<usize>)>,
356 key_range: Range<usize>,
357 line_begin_index: usize,
358 line_number: u32,
359 operator_index: usize,
360 ) -> Field {
361 Field {
362 content,
363 document_internals,
364 escape_operator_ranges,
365 key_range,
366 line_begin_index,
367 line_number,
368 operator_index,
369 touched: Cell::new(false),
370 }
371 }
372
373 fn set_content(&mut self, content: FieldContent) {
374 self.content = content;
375 }
376}
377
378impl SectionElement for Field {
379 fn as_element(&self) -> &dyn Element {
380 self
381 }
382
383 fn as_mut_field(&mut self) -> Option<&mut Field> {
384 Some(self)
385 }
386
387 fn key(&self) -> &str {
388 &self.document_internals.content[self.key_range.clone()]
389 }
390}