1use itertools::Itertools;
37use pest::{
38 error::Error,
39 iterators::{Pair, Pairs},
40 Parser,
41};
42use pest_derive::Parser;
43use std::{cmp::Ordering, collections::HashSet};
44
45#[derive(Parser)]
46#[grammar = "frame_format_grammar.pest"]
47struct FrameSequenceParser;
48
49pub fn parse_frame_sequence(input: &str) -> Result<Vec<isize>, Error<Rule>> {
53 FrameSequenceParser::parse(Rule::FrameSequenceString, input)
54 .map(|token_tree| remove_duplicates(frame_sequence_token_tree_to_frames(token_tree)))
55}
56
57fn chop(seq: &mut Vec<isize>, result: &mut Vec<isize>, elements: usize) {
58 if seq.len() < elements {
59 let mut new_seq = seq
60 .iter()
61 .tuple_windows()
62 .flat_map(|pair: (&isize, &isize)| {
63 let left = *pair.0;
64 let right = (*pair.0 + *pair.1) / 2;
65 if left < right {
66 result.push(right);
67 vec![left, right]
68 } else {
69 vec![left]
70 }
71 })
72 .collect::<Vec<_>>();
73 new_seq.push(*seq.last().unwrap());
74 if new_seq.len() < elements {
75 chop(&mut new_seq, result, elements);
76 }
77 *seq = new_seq;
78 }
79}
80
81pub(crate) fn binary_sequence(range: (isize, isize)) -> Vec<isize> {
82 match range.0.cmp(&range.1) {
83 Ordering::Less => {
84 let mut seq = vec![range.0, range.1];
85 let mut result = seq.clone();
86 chop(&mut seq, &mut result, (range.1 - range.0) as _);
87 result
88 }
89 Ordering::Greater => {
90 let mut seq = vec![range.1, range.0];
91 let mut result = seq.clone();
92 chop(&mut seq, &mut result, (range.0 - range.1) as _);
93 result.reverse();
94 result
95 }
96 Ordering::Equal => vec![range.0],
97 }
98}
99
100fn frame_to_number(frame: Pair<Rule>) -> isize {
101 frame.as_str().parse::<isize>().unwrap()
102}
103
104fn frame_sequence_token_tree_to_frames(pairs: Pairs<Rule>) -> Vec<isize> {
105 pairs
106 .into_iter()
107 .flat_map(|pair| {
108 match pair.as_rule() {
109 Rule::FrameSequenceString | Rule::FrameSequence | Rule::FrameSequencePart => {
110 frame_sequence_token_tree_to_frames(pair.into_inner())
111 }
112 Rule::FrameRange => {
113 let mut pairs = pair.into_inner();
114 let left = frame_to_number(pairs.next().unwrap());
115 let right = frame_to_number(pairs.next().unwrap());
116
117 if pairs.next().is_some() {
119 let pair = pairs.next().unwrap();
120 match pair.as_rule() {
121 Rule::PositiveNumber => {
122 let step = frame_to_number(pair);
123
124 match left.cmp(&right) {
125 Ordering::Less => {
126 (left..right + 1).step_by(step as _).collect::<Vec<_>>()
127 }
128 Ordering::Greater => (right..left + 1)
129 .rev()
130 .step_by(step as _)
131 .collect::<Vec<_>>(),
132 Ordering::Equal => vec![left],
133 }
134 }
135 Rule::BinarySequenceSymbol => binary_sequence((left, right)),
136 _ => unreachable!(),
137 }
138 } else if left < right {
139 (left..right + 1).collect::<Vec<_>>()
140 } else if right < left {
141 (right..left + 1).rev().collect::<Vec<_>>()
142 }
143 else {
145 vec![left]
146 }
147 }
148 Rule::Frame => vec![frame_to_number(pair)],
149 _ => vec![],
150 }
151 })
152 .collect::<Vec<_>>()
153}
154
155fn remove_duplicates(elements: Vec<isize>) -> Vec<isize> {
156 let mut set = HashSet::<isize>::new();
157 elements
158 .iter()
159 .filter_map(|e| {
160 if set.contains(e) {
161 None
162 } else {
163 set.insert(*e);
164 Some(*e)
165 }
166 })
167 .collect()
168}
169
170#[cfg(test)]
171mod tests {
172 #[test]
173 fn test_individual_frames() {
174 use crate::parse_frame_sequence;
175 let frames = parse_frame_sequence("1,2,3,5,8,13").unwrap();
176 assert_eq!([1, 2, 3, 5, 8, 13], frames.as_slice());
177 }
178
179 #[test]
180 fn test_frame_sequence() {
181 use crate::parse_frame_sequence;
182 let frames = parse_frame_sequence("10-15").unwrap();
183 assert_eq!([10, 11, 12, 13, 14, 15], frames.as_slice());
184 }
185
186 #[test]
187 fn test_fram_sequence_with_step() {
188 use crate::parse_frame_sequence;
189 let frames = parse_frame_sequence("10-20@2").unwrap();
190 assert_eq!([10, 12, 14, 16, 18, 20], frames.as_slice());
191 }
192
193 #[test]
194 fn test_frame_sequence_with_step_reversed() {
195 use crate::parse_frame_sequence;
196 let frames = parse_frame_sequence("42-33@3").unwrap();
197 assert_eq!([42, 39, 36, 33], frames.as_slice());
198 }
199
200 #[test]
201 fn test_binary_frame_sequence() {
202 use crate::parse_frame_sequence;
203 let frames = parse_frame_sequence("10-20@b").unwrap();
204 assert_eq!(
205 [10, 20, 15, 12, 17, 11, 13, 16, 18, 14, 19],
206 frames.as_slice()
207 );
208 }
209
210 #[test]
211 fn test_multi_sequence() {
212 use crate::parse_frame_sequence;
213 let frames = parse_frame_sequence("10-20@2,42-33@3").unwrap();
214 assert_eq!([10, 12, 14, 16, 18, 20, 42, 39, 36, 33], frames.as_slice());
215 }
216
217 #[test]
218 fn test_multi_sequence_x() {
219 use crate::parse_frame_sequence;
220 let frames = parse_frame_sequence("10-20x2,42-33x3").unwrap();
221 assert_eq!([10, 12, 14, 16, 18, 20, 42, 39, 36, 33], frames.as_slice());
222 }
223}