repline/
iter.rs

1//! Shmancy iterator adapters
2
3pub use chars::Chars;
4pub use flatten::Flatten;
5
6pub mod chars {
7    //! Converts an <code>[Iterator]<Item = [u8]></code> into an
8    //! <code>[Iterator]<Item = [Result]<[char], [BadUnicode]>></code>
9
10    /// Invalid unicode codepoint found when iterating over [Chars]
11    #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
12    pub struct BadUnicode(pub u32);
13    impl std::error::Error for BadUnicode {}
14    impl std::fmt::Display for BadUnicode {
15        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16            let Self(code) = self;
17            write!(f, "Bad unicode: {code}")
18        }
19    }
20
21    /// Converts an <code>[Iterator]<Item = [u8]></code> into an
22    /// <code>[Iterator]<Item = [char]></code>
23    #[derive(Clone, Debug)]
24    pub struct Chars<I: Iterator<Item = u8>>(pub I);
25    impl<I: Iterator<Item = u8>> Iterator for Chars<I> {
26        type Item = Result<char, BadUnicode>;
27        fn next(&mut self) -> Option<Self::Item> {
28            let Self(bytes) = self;
29            let start = bytes.next()? as u32;
30            let (mut out, count) = match start {
31                start if start & 0x80 == 0x00 => (start, 0), // ASCII valid range
32                start if start & 0xe0 == 0xc0 => (start & 0x1f, 1), // 1 continuation byte
33                start if start & 0xf0 == 0xe0 => (start & 0x0f, 2), // 2 continuation bytes
34                start if start & 0xf8 == 0xf0 => (start & 0x07, 3), // 3 continuation bytes
35                _ => return None,
36            };
37            for _ in 0..count {
38                let cont = bytes.next()? as u32;
39                if cont & 0xc0 != 0x80 {
40                    return None;
41                }
42                out = (out << 6) | (cont & 0x3f);
43            }
44            Some(char::from_u32(out).ok_or(BadUnicode(out)))
45        }
46    }
47}
48pub mod flatten {
49    //! Flattens an [Iterator] returning [`Result<T, E>`](Result) or [`Option<T>`](Option)
50    //! into a *non-[FusedIterator](std::iter::FusedIterator)* over `T`
51
52    /// Flattens an [Iterator] returning [`Result<T, E>`](Result) or [`Option<T>`](Option)
53    /// into a *non-[FusedIterator](std::iter::FusedIterator)* over `T`
54    #[derive(Clone, Debug)]
55    pub struct Flatten<T, I: Iterator<Item = T>>(pub I);
56    impl<T, E, I: Iterator<Item = Result<T, E>>> Iterator for Flatten<Result<T, E>, I> {
57        type Item = T;
58        fn next(&mut self) -> Option<Self::Item> {
59            self.0.next()?.ok()
60        }
61    }
62    impl<T, I: Iterator<Item = Option<T>>> Iterator for Flatten<Option<T>, I> {
63        type Item = T;
64        fn next(&mut self) -> Option<Self::Item> {
65            self.0.next()?
66        }
67    }
68}