1 | use core::iter::Peekable; |
2 | |
3 | /// An iterator that skips all leading zeros. |
4 | /// |
5 | /// When the wrapped iterator is all zeros, then the last item is retained. |
6 | pub struct LeadingZerosStripped<I> |
7 | where |
8 | I: Iterator, |
9 | { |
10 | inner: Peekable<I>, |
11 | } |
12 | |
13 | impl<I> Clone for LeadingZerosStripped<I> |
14 | where |
15 | I: Iterator, |
16 | Peekable<I>: Clone, |
17 | { |
18 | fn clone(&self) -> Self { |
19 | Self { |
20 | inner: self.inner.clone(), |
21 | } |
22 | } |
23 | } |
24 | |
25 | impl<I> LeadingZerosStripped<I> |
26 | where |
27 | I: ExactSizeIterator<Item = u8>, |
28 | { |
29 | pub fn new(inner: I) -> Self { |
30 | let mut len: usize = inner.len(); |
31 | let mut inner: impl Iterator = inner.peekable(); |
32 | // Strip all leading zeroes, but don't strip the last byte if all bytes |
33 | // were zero. |
34 | while len > 1 && inner.next_if_eq(&0).is_some() { |
35 | len -= 1; |
36 | } |
37 | Self { inner } |
38 | } |
39 | } |
40 | |
41 | impl<I> Iterator for LeadingZerosStripped<I> |
42 | where |
43 | I: Iterator, |
44 | { |
45 | type Item = I::Item; |
46 | |
47 | fn next(&mut self) -> Option<Self::Item> { |
48 | self.inner.next() |
49 | } |
50 | |
51 | fn size_hint(&self) -> (usize, Option<usize>) { |
52 | self.inner.size_hint() |
53 | } |
54 | } |
55 | |
56 | impl<I> ExactSizeIterator for LeadingZerosStripped<I> where I: ExactSizeIterator {} |
57 | |
58 | #[cfg (test)] |
59 | mod tests { |
60 | use super::*; |
61 | |
62 | #[test ] |
63 | fn test_leading_zeroes_stripped() { |
64 | static TEST_CASES: &[(&[u8], &[u8])] = &[ |
65 | (&[], &[]), |
66 | (&[0], &[0]), |
67 | (&[0, 1], &[1]), |
68 | (&[0, 0, 1], &[1]), |
69 | (&[0, 0, 0, 1], &[1]), |
70 | (&[1, 0], &[1, 0]), |
71 | (&[0, 1, 0], &[1, 0]), |
72 | ]; |
73 | TEST_CASES.iter().copied().for_each(|(input, expected)| { |
74 | let stripped = LeadingZerosStripped::new(input.iter().copied()); |
75 | super::super::test::assert_iterator(stripped, expected); |
76 | }); |
77 | } |
78 | } |
79 | |