1use std::fmt;
42use std::io::BufRead;
43use std::iter::Iterator;
44
45#[cfg(feature = "serde-derive")]
46extern crate serde;
47
48use crate::line::{Line, LineReader};
50
51#[derive(Debug, Error)]
52pub enum PropertyError {
53 #[error("Line {}: Missing property name.", line)]
54 MissingName { line: usize },
55 #[error("Line {}: Missing a closing quote.", line)]
56 MissingClosingQuote { line: usize },
57 #[error("Line {}: Missing a \"{}\" delimiter.", line, delimiter)]
58 MissingDelimiter { line: usize, delimiter: char },
59 #[error("Line {}: Missing content after \"{}\".", line, letter)]
60 MissingContentAfter { line: usize, letter: char },
61 #[error("Line {}: Missing a parameter key.", line)]
62 MissingParamKey { line: usize },
63}
64
65#[derive(Debug, Clone, Default)]
67#[cfg_attr(feature = "serde-derive", derive(serde::Serialize, serde::Deserialize))]
68pub struct Property {
69 pub name: String,
71 pub params: Option<Vec<(String, Vec<String>)>>,
73 pub value: Option<String>,
75}
76
77impl Property {
78 pub fn new() -> Property {
80 Property {
81 name: String::new(),
82 params: None,
83 value: None,
84 }
85 }
86}
87
88impl fmt::Display for Property {
89 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
90 write!(
91 f,
92 "name: {}\nparams: {:?}\nvalue: {:?}",
93 self.name, self.params, self.value
94 )
95 }
96}
97
98#[derive(Debug, Clone)]
100pub struct PropertyParser<B> {
101 line_reader: LineReader<B>,
102}
103
104impl<B: BufRead> PropertyParser<B> {
105 pub fn new(line_reader: LineReader<B>) -> PropertyParser<B> {
107 PropertyParser { line_reader }
108 }
109
110 pub fn from_reader(reader: B) -> PropertyParser<B> {
112 let line_reader = LineReader::new(reader);
113
114 PropertyParser { line_reader }
115 }
116
117 fn parse(&self, line: Line) -> Result<Property, PropertyError> {
118 let mut property = Property::new();
119
120 let mut to_parse = line.as_str();
121
122 let end_name_index;
124
125 let mut param_index = to_parse
126 .find(::PARAM_DELIMITER)
127 .unwrap_or(usize::max_value());
128 let mut value_index = to_parse
129 .find(::VALUE_DELIMITER)
130 .unwrap_or(usize::max_value());
131
132 if param_index < value_index && param_index != 0 {
133 end_name_index = param_index;
134 } else if value_index != usize::max_value() && value_index != 0 {
135 end_name_index = value_index;
136 } else {
137 return Err(PropertyError::MissingName {
138 line: line.number(),
139 })
140 .into();
141 }
142
143 {
144 let split = to_parse.split_at(end_name_index);
145 property.name = split.0.to_string();
146 to_parse = split.1;
147 }
148
149 value_index = to_parse
151 .find(::VALUE_DELIMITER)
152 .unwrap_or(usize::max_value());
153 param_index = to_parse
154 .find(::PARAM_DELIMITER)
155 .unwrap_or(usize::max_value());
156
157 if param_index != usize::max_value() && value_index > param_index {
160 let mut param_list = Vec::new();
161
162 while to_parse.starts_with(::PARAM_DELIMITER) {
163 to_parse = to_parse.trim_start_matches(::PARAM_DELIMITER);
164
165 let mut param_elements = to_parse.splitn(2, ::PARAM_NAME_DELIMITER);
167
168 let key = param_elements
169 .next()
170 .and_then(|key| {
171 if key.is_empty() {
172 return None;
173 }
174
175 Some(key)
176 })
177 .ok_or_else(|| PropertyError::MissingParamKey {
178 line: line.number(),
179 })?;
180
181 to_parse =
182 param_elements
183 .next()
184 .ok_or_else(|| PropertyError::MissingDelimiter {
185 delimiter: ::PARAM_NAME_DELIMITER,
186 line: line.number(),
187 })?;
188
189 let mut values = Vec::new();
190
191 let mut i = 10;
192
193 while i > 0 {
195 i -= 1;
196 if to_parse.starts_with('"') {
197 let mut elements = to_parse.splitn(3, ::PARAM_QUOTE).skip(1);
199 values.push(
201 elements
202 .next()
203 .ok_or_else(|| PropertyError::MissingClosingQuote {
204 line: line.number(),
205 })?
206 .to_string(),
207 );
208
209 to_parse =
210 elements
211 .next()
212 .ok_or_else(|| PropertyError::MissingClosingQuote {
213 line: line.number(),
214 })?
215 } else {
216 let param_delimiter = to_parse
220 .find(::PARAM_DELIMITER)
221 .unwrap_or(usize::max_value());
222 let value_delimiter = to_parse
223 .find(::VALUE_DELIMITER)
224 .unwrap_or(usize::max_value());
225 let param_value_delimiter = to_parse
226 .find(::PARAM_VALUE_DELIMITER)
227 .unwrap_or(usize::max_value());
228
229 let end_param_value = {
230 if param_value_delimiter < value_delimiter
231 && param_value_delimiter < param_delimiter
232 {
233 Ok(param_value_delimiter)
234 } else if param_delimiter < value_delimiter
235 && param_delimiter < param_value_delimiter
236 {
237 Ok(param_delimiter)
238 } else if value_delimiter != usize::max_value() {
239 Ok(value_delimiter)
240 } else {
241 Err(PropertyError::MissingContentAfter {
242 letter: ::PARAM_NAME_DELIMITER,
243 line: line.number(),
244 })
245 }
246 }?;
247
248 let elements = to_parse.split_at(end_param_value);
249 values.push(elements.0.to_string());
250 to_parse = elements.1;
251 }
252
253 if !to_parse.starts_with(::PARAM_VALUE_DELIMITER) {
254 break;
255 }
256
257 to_parse = to_parse.trim_start_matches(::PARAM_VALUE_DELIMITER);
258 }
259
260 param_list.push((key.to_uppercase(), values));
261 }
262
263 property.params = Some(param_list);
264 } else {
265 property.params = None;
266 }
267
268 to_parse = to_parse.trim_start_matches(::VALUE_DELIMITER);
270 if to_parse.is_empty() {
271 property.value = None;
272 } else {
273 property.value = Some(to_parse.to_string());
274 }
275
276 Ok(property)
277 }
278}
279
280impl<B: BufRead> Iterator for PropertyParser<B> {
281 type Item = Result<Property, PropertyError>;
282
283 fn next(&mut self) -> Option<Result<Property, PropertyError>> {
284 self.line_reader.next().map(|line| self.parse(line))
285 }
286}