1use crate::non_empty_vec::NonEmptyVec;
22use std::mem;
23
24pub type DepthList<L, T> = Vec<DepthItem<L, T>>;
25
26#[derive(Debug, Clone, PartialEq, Eq)]
27pub enum DepthItem<L, T> {
28 Item(T),
29 List(L, DepthList<L, T>),
30}
31
32#[derive(Debug)]
33struct DepthStack<L, T> {
34 finished: Vec<(L, DepthList<L, T>)>,
35 stack: NonEmptyVec<(L, Vec<DepthItem<L, T>>)>,
36}
37
38impl<L, T> DepthStack<L, T>
39where
40 L: Copy,
41{
42 #[inline]
43 pub fn new(top_ltype: L) -> Self {
44 DepthStack {
45 finished: Vec::new(),
46 stack: NonEmptyVec::new((top_ltype, Vec::new())),
47 }
48 }
49
50 pub fn increase_depth(&mut self, ltype: L) {
51 self.stack.push((ltype, Vec::new()));
52 }
53
54 pub fn decrease_depth(&mut self) {
55 let (ltype, list) = self.stack.pop().expect("No depth to pop off!");
56 self.push(DepthItem::List(ltype, list));
57 }
58
59 pub fn new_list(&mut self, ltype: L) {
60 if self.stack.is_single() {
61 self.finish_depth_list(Some(ltype));
66 } else {
67 self.decrease_depth();
69 self.increase_depth(ltype);
70 }
71 }
72
73 fn push(&mut self, item: DepthItem<L, T>) {
74 self.stack.last_mut().1.push(item);
75 }
76
77 #[inline]
78 pub fn push_item(&mut self, item: T) {
79 self.push(DepthItem::Item(item));
80 }
81
82 #[inline]
83 pub fn last_type(&self) -> L {
84 self.stack.last().0
85 }
86
87 fn finish_depth_list(&mut self, new_ltype: Option<L>) {
88 for _ in 1..self.stack.len() {
91 self.decrease_depth();
92 }
93
94 debug_assert!(
95 self.stack.is_single(),
96 "Open layers remain after collapsing",
97 );
98
99 let (ltype, list) = {
101 let new_ltype = new_ltype.unwrap_or(self.stack.first().0);
106
107 mem::replace(self.stack.first_mut(), (new_ltype, Vec::new()))
108 };
109
110 if !list.is_empty() {
112 self.finished.push((ltype, list));
113 }
114 }
115
116 pub fn into_trees(mut self) -> Vec<(L, DepthList<L, T>)> {
117 self.finish_depth_list(None);
118 self.finished
119 }
120}
121
122pub fn process_depths<I, L, T>(top_ltype: L, items: I) -> Vec<(L, DepthList<L, T>)>
123where
124 I: IntoIterator<Item = (usize, L, T)>,
125 L: Copy + PartialEq,
126{
127 let mut stack = DepthStack::new(top_ltype);
128
129 let mut previous = 0;
131
132 for (depth, ltype, item) in items {
134 for _ in previous..depth {
144 stack.increase_depth(ltype);
145 }
146
147 for _ in depth..previous {
149 stack.decrease_depth();
150 }
151
152 if stack.last_type() != ltype {
161 stack.new_list(ltype);
162 }
163
164 stack.push_item(item);
166 previous = depth;
167 }
168
169 stack.into_trees()
170}
171
172#[test]
173fn depth() {
174 macro_rules! test {
175 ($depths:expr, $list:expr $(,)?) => {{
176 let depths: Vec<_> = $depths
178 .into_iter()
179 .map(|(depth, item)| (depth, (), item))
180 .collect();
181
182 let list: Vec<DepthItem<(), char>> = $list;
184 let expected = ((), list);
185 let actual = process_depths((), depths);
186 assert_eq!(
187 actual.len(),
188 1,
189 "Actual produced finished list doesn't have exactly one element",
190 );
191
192 assert_eq!(
193 &actual[0], &expected,
194 "Actual produced depth list doesn't match expected",
195 );
196 }};
197 }
198
199 macro_rules! item {
200 ($item:expr) => {
201 DepthItem::Item($item)
202 };
203 }
204
205 macro_rules! list {
206 () => {
207 DepthItem::List((), vec![])
208 };
209 ($($x:expr),+ $(,)?) => {
210 DepthItem::List((), vec![$($x),+])
211 };
212 }
213
214 test!(
215 vec![(0, 'a')], vec![item!('a')],
217 );
218 test!(
219 vec![(0, 'a'), (0, 'b')], vec![item!('a'), item!('b')],
221 );
222 test!(
223 vec![(0, 'a'), (0, 'b'), (1, 'c')],
224 vec![item!('a'), item!('b'), list![item!('c')]]
225 );
226 test!(
227 vec![(0, 'a'), (0, 'b'), (2, 'c')],
228 vec![item!('a'), item!('b'), list![list![item!('c')]]],
229 );
230 test!(
231 vec![(1, 'a'), (1, 'b')],
232 vec![list![item!('a'), item!('b')]],
233 );
234 test!(
235 vec![(2, 'a'), (2, 'b')],
236 vec![list![list![item!('a'), item!('b')]]],
237 );
238 test!(
239 vec![(2, 'a'), (1, 'b')],
240 vec![list![list![item!('a')], item!('b')]],
241 );
242 test!(
243 vec![(5, 'a')],
244 vec![list![list![list![list![list![item!('a')]]]]]],
245 );
246 test!(
247 vec![(2, 'a'), (3, 'b'), (1, 'c'), (1, 'd'), (2, 'e'), (0, 'f')],
248 vec![
249 list![
250 list![item!('a'), list![item!('b')]],
251 item!('c'),
252 item!('d'),
253 list![item!('e')],
254 ],
255 item!('f'),
256 ],
257 );
258}
259
260#[test]
261fn depth_types() {
262 macro_rules! test {
263 ($depths:expr, $list:expr $(,)?) => {{
264 let expected: Vec<(char, Vec<DepthItem<char, char>>)> = $list;
265 let actual = process_depths(' ', $depths);
266
267 assert_eq!(
268 actual, expected,
269 "Actual produced depth list doesn't match expected",
270 );
271 }};
272 }
273
274 macro_rules! item {
275 ($item:expr) => {
276 DepthItem::Item($item)
277 };
278 }
279
280 macro_rules! list {
281 () => {
282 DepthItem::List((), vec![])
283 };
284 ($ltype:expr, $($x:expr),+ $(,)?) => {
285 DepthItem::List($ltype, vec![$($x),+])
286 };
287 }
288
289 test!(vec![], vec![]);
290 test!(
291 vec![(0, '*', 'a')], vec![('*', vec![item!('a')])],
293 );
294 test!(
295 vec![(0, '*', 'a'), (0, '*', 'b')], vec![('*', vec![item!('a'), item!('b')])],
297 );
298 test!(
299 vec![(0, '*', 'a'), (0, '#', 'b')], vec![('*', vec![item!('a')]), ('#', vec![item!('b')])],
301 );
302 test!(
303 vec![(1, '*', 'a'), (1, '#', 'b')],
304 vec![(' ', vec![list!['*', item!('a')], list!['#', item!('b')]])],
305 );
306 test!(
307 vec![(1, '*', 'a'), (1, '#', 'b'), (0, '*', 'c')],
308 vec![
309 (' ', vec![list!['*', item!('a')], list!['#', item!('b')]]),
310 ('*', vec![item!('c')]),
311 ],
312 );
313 test!(
314 vec![(2, '*', 'a'), (2, '#', 'b')],
315 vec![(
316 ' ',
317 vec![list!['*', list!['*', item!('a')], list!['#', item!('b')]]]
318 )],
319 );
320 test!(
321 vec![(0, '#', 'a'), (2, '*', 'b'), (2, '*', 'c'), (1, '*', 'd')],
322 vec![(
323 '#',
324 vec![
325 item!('a'),
326 list!['*', list!['*', item!('b'), item!('c')], item!('d')],
327 ],
328 )],
329 );
330 test!(
331 vec![(0, '#', 'a'), (0, '#', 'b'), (0, '*', 'c'), (1, '#', 'd')],
332 vec![
333 ('#', vec![item!('a'), item!('b')]),
334 ('*', vec![item!('c'), list!['#', item!('d')]]),
335 ],
336 );
337}
338
339#[cfg(test)]
340mod test {
341 use super::*;
342 use proptest::prelude::*;
343
344 macro_rules! test {
345 ($depths:expr) => {{
346 let depths_input = $depths;
347 let expected_length = depths_input.len();
348 let depth_list = process_depths(900, depths_input);
349
350 fn count(list: &DepthList<i32, String>) -> usize {
352 list.iter()
353 .map(|item| match item {
354 DepthItem::Item(_) => 1,
355 DepthItem::List(_, list) => count(&list),
356 })
357 .sum()
358 }
359
360 let actual_length: usize =
361 depth_list.iter().map(|(_, list)| count(list)).sum();
362
363 assert_eq!(
365 actual_length, expected_length,
366 "Actual depth list output doesn't match input",
367 );
368 }};
369 }
370
371 fn arb_depth(max_depth: usize) -> impl Strategy<Value = Vec<(usize, i32, String)>> {
372 prop::collection::vec((0..max_depth, 901..902, "[a-z]{3}"), 0..100)
373 }
374
375 proptest! {
376 #![proptest_config(ProptestConfig::with_cases(4096))]
377
378 #[test]
379 #[ignore = "slow test"]
380 fn deep_depth_prop(depths in arb_depth(128)) {
381 test!(depths);
382 }
383
384 #[test]
385 #[ignore = "slow test"]
386 fn shallow_depth_prop(depths in arb_depth(4)) {
387 test!(depths);
388 }
389 }
390}