1use 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.
6pub struct LeadingZerosStripped<I>
7where
8 I: Iterator,
9{
10 inner: Peekable<I>,
11}
12
13impl<I> Clone for LeadingZerosStripped<I>
14where
15 I: Iterator,
16 Peekable<I>: Clone,
17{
18 fn clone(&self) -> Self {
19 Self {
20 inner: self.inner.clone(),
21 }
22 }
23}
24
25impl<I> LeadingZerosStripped<I>
26where
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
41impl<I> Iterator for LeadingZerosStripped<I>
42where
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
56impl<I> ExactSizeIterator for LeadingZerosStripped<I> where I: ExactSizeIterator {}
57
58#[cfg(test)]
59mod 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