1use std::fmt::Debug;
2use std::str::FromStr;
3use std::{borrow::Cow, char::CharTryFromError, iter};
4
5use itertools::{Itertools, MultiProduct};
6use nom_language::error::{convert_error, VerboseError};
7
8mod parser;
9mod sequence;
10
11#[derive(Clone, Debug)]
13struct List<'a>(Vec<Part<'a>>);
14
15impl<'a> List<'a> {
16 fn into_owned(self) -> List<'static> {
17 List(self.0.into_iter().map(Part::into_owned).collect())
18 }
19}
20
21impl<'a> IntoIterator for List<'a> {
22 type Item = Result<Cow<'a, str>, CharTryFromError>;
23
24 type IntoIter = iter::Flatten<<Vec<Part<'a>> as IntoIterator>::IntoIter>;
25
26 fn into_iter(self) -> Self::IntoIter {
27 self.0.into_iter().flatten()
28 }
29}
30
31impl std::fmt::Display for List<'_> {
32 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
33 f.write_str("{")?;
34 let mut parts = self.0.iter();
35 if let Some(part) = parts.next() {
36 write!(f, "{part}")?;
37 }
38 for part in parts {
39 write!(f, ",{part}")?;
40 }
41 f.write_str("}")?;
42 Ok(())
43 }
44}
45
46#[derive(Clone, Copy, Debug)]
47enum Sequence {
48 Int {
49 width: Option<usize>,
50 sequence: sequence::Sequence<i64>,
51 },
52 Char(sequence::Sequence<char>),
53}
54
55#[derive(Clone, Copy, Debug)]
56enum SequenceIterator {
57 Int {
58 width: Option<usize>,
59 sequence: sequence::SequenceIterator<i64>,
60 },
61 Char(sequence::SequenceIterator<char>),
62}
63
64impl IntoIterator for Sequence {
65 type Item = Result<String, CharTryFromError>;
66
67 type IntoIter = SequenceIterator;
68
69 fn into_iter(self) -> Self::IntoIter {
70 match self {
71 Sequence::Int { width, sequence } => SequenceIterator::Int {
72 width,
73 sequence: sequence.into_iter(),
74 },
75 Sequence::Char(s) => SequenceIterator::Char(s.into_iter()),
76 }
77 }
78}
79
80impl Iterator for SequenceIterator {
81 type Item = Result<String, <u32 as TryInto<char>>::Error>;
82
83 fn next(&mut self) -> Option<Self::Item> {
84 match self {
85 SequenceIterator::Int { width, sequence } => {
86 sequence.next().map(|number| match *width {
87 Some(width) => Ok(format!(
88 "{number:0width$}",
89 number = number.unwrap(),
90 width = width,
91 )),
92 None => Ok(number.unwrap().to_string()),
93 })
94 }
95 SequenceIterator::Char(i) => i.next().map(|r| r.map(|c| c.to_string())),
96 }
97 }
98}
99
100impl std::fmt::Display for Sequence {
101 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
102 f.write_str("{")?;
103 match *self {
104 Self::Int {
105 width,
106 sequence: sequence::Sequence { start, end, incr },
107 } => {
108 if width.is_some() {
109 f.write_str("=")?;
110 }
111 write!(f, "{start}..{end}")?;
112 if incr != 1 {
113 write!(f, "..{incr}")?;
114 }
115 }
116 Self::Char(sequence::Sequence { start, end, incr }) => {
117 let escaped = ",.{}\\";
118 if escaped.contains(start) {
119 f.write_str("\\")?;
120 }
121 write!(f, "{start}..")?;
122 if escaped.contains(end) {
123 f.write_str("\\")?;
124 }
125 write!(f, "{end}")?;
126 if incr != 1 {
127 write!(f, "..{incr}")?;
128 }
129 }
130 }
131 f.write_str("}")?;
132 Ok(())
133 }
134}
135
136#[derive(Clone, Debug)]
142pub struct Expression<'a>(Vec<Part<'a>>);
143
144impl<'a> Expression<'a> {
145 fn into_owned(self) -> Expression<'static> {
146 Expression(self.0.into_iter().map(Part::into_owned).collect())
147 }
148}
149
150impl FromStr for Expression<'static> {
151 type Err = String;
152
153 fn from_str(s: &str) -> Result<Self, Self::Err> {
154 let expression: Expression = s.try_into()?;
155 Ok(expression.into_owned())
156 }
157}
158
159impl<'a> TryFrom<&'a str> for Expression<'a> {
160 type Error = String;
161
162 fn try_from(value: &'a str) -> Result<Self, Self::Error> {
163 let output = parser::expression::<VerboseError<&str>>(value);
164 match output {
165 Ok((_, expression)) => Ok(expression),
166 Err(nom::Err::Error(e) | nom::Err::Failure(e)) => return Err(convert_error(value, e)),
167 _ => panic!("Somehow got an incomplete"),
168 }
169 }
170}
171
172impl<'a> IntoIterator for Expression<'a> {
173 type Item = Result<Cow<'a, str>, CharTryFromError>;
174
175 type IntoIter = ExpressionIterator<'a>;
176
177 fn into_iter(self) -> Self::IntoIter {
178 ExpressionIterator(self.0.into_iter().multi_cartesian_product())
179 }
180}
181
182impl std::fmt::Display for Expression<'_> {
183 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
184 for part in &self.0 {
185 write!(f, "{part}")?;
186 }
187 Ok(())
188 }
189}
190
191#[derive(Clone, Debug)]
192pub struct ExpressionIterator<'a>(MultiProduct<PartIterator<'a>>);
193
194impl<'a> Iterator for ExpressionIterator<'a> {
195 type Item = Result<Cow<'a, str>, CharTryFromError>;
196
197 fn next(&mut self) -> Option<Self::Item> {
198 self.0.next().map(|parts| match parts.len() {
199 0 => Ok(Cow::Borrowed("")),
200 1 => parts.into_iter().next().unwrap(),
201 _ => {
202 let parts: Result<Vec<_>, _> = parts.into_iter().collect();
203 let parts = parts?;
204 let mut string = String::with_capacity(parts.iter().map(|s| s.len()).sum());
205 for part in parts {
206 string.push_str(&part);
207 }
208 Ok(Cow::Owned(string))
209 }
210 })
211 }
212}
213
214#[derive(Clone, Debug)]
215enum Part<'a> {
216 Plain(Cow<'a, str>),
217 List(List<'a>),
218 Sequence(Sequence),
219 Expression(Expression<'a>),
220}
221
222impl<'a> Part<'a> {
223 fn into_owned(self) -> Part<'static> {
224 match self {
225 Part::Plain(part) => Part::Plain(Cow::Owned(part.into_owned())),
226 Part::List(part) => Part::List(part.into_owned()),
227 Part::Sequence(part) => Part::Sequence(part),
228 Part::Expression(part) => Part::Expression(part.into_owned()),
229 }
230 }
231}
232
233#[derive(Clone, Debug)]
234enum PartIterator<'a> {
235 Plain(iter::Once<Cow<'a, str>>),
236 List(Box<<List<'a> as IntoIterator>::IntoIter>),
237 Sequence(<Sequence as IntoIterator>::IntoIter),
238 Expression(<Expression<'a> as IntoIterator>::IntoIter),
239}
240
241impl<'a> IntoIterator for Part<'a> {
242 type Item = Result<Cow<'a, str>, CharTryFromError>;
243
244 type IntoIter = PartIterator<'a>;
245
246 fn into_iter(self) -> Self::IntoIter {
247 match self {
248 Part::Plain(part) => PartIterator::Plain(iter::once(part.clone())),
249 Part::List(part) => PartIterator::List(Box::new(part.into_iter())),
250 Part::Sequence(part) => PartIterator::Sequence(part.into_iter()),
251 Part::Expression(part) => PartIterator::Expression(part.into_iter()),
252 }
253 }
254}
255
256impl<'a> Iterator for PartIterator<'a> {
257 type Item = Result<Cow<'a, str>, CharTryFromError>;
258
259 fn next(&mut self) -> Option<Self::Item> {
260 match self {
261 PartIterator::Plain(part) => part.next().map(|s| Ok(s)),
262 PartIterator::List(part) => part.next(),
263 PartIterator::Sequence(part) => part.next().map(|r| r.map(|s| Cow::Owned(s))),
264 PartIterator::Expression(part) => part.next(),
265 }
266 }
267}
268
269impl std::fmt::Display for Part<'_> {
270 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
271 match self {
272 Self::Plain(s) => {
273 for c in s.chars() {
274 if ",{}\\".contains(c) {
275 f.write_str("\\")?;
276 }
277 write!(f, "{c}")?;
278 }
279 }
280 Self::List(l) => write!(f, "{l}")?,
281 Self::Sequence(s) => write!(f, "{s}")?,
282 Self::Expression(e) => write!(f, "{e}")?,
283 }
284 Ok(())
285 }
286}
287
288#[cfg(test)]
289mod tests {
290 use super::*;
291
292 #[test]
293 fn test_simple_list() {
294 let expression: Expression = "{a,b,c}".try_into().unwrap();
295 let generated: Result<Vec<_>, _> = expression.into_iter().collect();
296 let expected: Vec<_> = vec!["a", "b", "c"];
297 assert_eq!(generated.unwrap(), expected);
298 }
299 #[test]
300 fn test_simple_list_empties() {
301 let expression: Expression = "{a,,,b,c}".try_into().unwrap();
302 let generated: Result<Vec<_>, _> = expression.into_iter().collect();
303 let expected: Vec<_> = vec!["a", "", "", "b", "c"];
304 assert_eq!(generated.unwrap(), expected);
305 }
306
307 #[test]
308 fn test_list_escapes() {
309 let expression: Expression = r"{a,b\,c,d\{e,f\}\\g}".try_into().unwrap();
310 let generated: Result<Vec<_>, _> = expression.into_iter().collect();
311 let expected: Vec<_> = vec!["a", "b,c", "d{e", r"f}\g"];
312 assert_eq!(generated.unwrap(), expected);
313 }
314 #[test]
315 fn test_nested_list() {
316 let expression: Expression = r"s{a,b{,c,d{e,f}g,h{i,j{k}l,m{}n}o}p,q}r"
317 .try_into()
318 .unwrap();
319 let generated: Result<Vec<_>, _> = expression.into_iter().collect();
320 let expected: Vec<_> = vec![
321 "sar",
322 "sbpr",
323 "sbcpr",
324 "sbdegpr",
325 "sbdfgpr",
326 "sbhiopr",
327 "sbhjklopr",
328 "sbhmnopr",
329 "sqr",
330 ];
331 assert_eq!(generated.unwrap(), expected);
332 }
333 #[test]
334 fn test_list_with_empty_part() {
335 let expression: Expression = "{a,,c}".try_into().unwrap();
336 let generated: Result<Vec<_>, _> = expression.into_iter().collect();
337 let expected: Vec<_> = vec!["a", "", "c"];
338 assert_eq!(generated.unwrap(), expected);
339 }
340 #[test]
341 fn test_expression() {
342 let expression: Expression = "a{b,c,}d{1..2}e".try_into().unwrap();
343 let generated: Result<Vec<_>, _> = expression.into_iter().collect();
344 let expected = vec!["abd1e", "abd2e", "acd1e", "acd2e", "ad1e", "ad2e"];
345 assert_eq!(generated.unwrap(), expected);
346 }
347 #[test]
348 fn test_char_sequence() {
349 let expression: Expression = "a{d..f}g".try_into().unwrap();
350 let generated: Result<Vec<_>, _> = expression.into_iter().collect();
351 let expected = vec!["adg", "aeg", "afg"];
352 assert_eq!(generated.unwrap(), expected);
353 }
354 #[test]
355 fn test_negative_number_sequence() {
356 let expression: Expression = "a{-10..10..3}g".try_into().unwrap();
357 let generated: Result<Vec<_>, _> = expression.into_iter().collect();
358 let expected = vec!["a-10g", "a-7g", "a-4g", "a-1g", "a2g", "a5g", "a8g"];
359 assert_eq!(generated.unwrap(), expected);
360 }
361 #[test]
362 fn test_decreasing_negative_number_sequence() {
363 let expression: Expression = "a{-10..10..3}g".try_into().unwrap();
364 let generated: Result<Vec<_>, _> = expression.into_iter().collect();
365 let expected = vec!["a-10g", "a-7g", "a-4g", "a-1g", "a2g", "a5g", "a8g"];
366 assert_eq!(generated.unwrap(), expected);
367 }
368 #[test]
369 fn test_escaped_char_sequence() {
370 let expression: Expression = r"a{z..\}}b{\...\{..77}c".try_into().unwrap();
371 let generated: Result<Vec<_>, _> = expression.into_iter().collect();
372 let expected = vec![
373 "azb.c", "azb{c", "a{b.c", "a{b{c", "a|b.c", "a|b{c", "a}b.c", "a}b{c",
374 ];
375 assert_eq!(generated.unwrap(), expected);
376 }
377
378 #[test]
379 fn test_equal_width_negative() {
380 let expression: Expression = r"{=-1..1000..300}".try_into().unwrap();
381 let generated: Result<Vec<_>, _> = expression.into_iter().collect();
382 let expected = vec!["-001", "0299", "0599", "0899"];
383 assert_eq!(generated.unwrap(), expected);
384 }
385
386 #[test]
387 fn test_display() {
388 let test_cases = [
389 "{a,b,c}",
390 "{a,,,b,c}",
391 r"{a,b\,c,d\{e,f\}\\g}",
392 r"s{a,b{,c,d{e,f}g,h{i,j{k}l,m{}n}o}p,q}r",
393 "{a,,c}",
394 "a{b,c,}d{1..2}e",
395 "a{d..f}g",
396 "a{-10..10..3}g",
397 "a{-10..10..3}g",
398 r"a{z..\}}b{\...\{..77}c",
399 r"{=-1..1000..300}",
400 ];
401 for test_case in test_cases {
402 assert_eq!(
403 Expression::try_from(test_case).unwrap().to_string(),
404 test_case,
405 );
406 }
407 }
408}