ring/polyfill/
leading_zeros_skipped.rs

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 = inner.len();
31        let mut inner = 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}