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