//! Shmancy iterator adapters
pub use chars::Chars;
pub use flatten::Flatten;
pub mod chars {
//! Converts an [Iterator]
into an
//! [Iterator]- >
/// Invalid unicode codepoint found when iterating over [Chars]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub struct BadUnicode(pub u32);
impl std::error::Error for BadUnicode {}
impl std::fmt::Display for BadUnicode {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let Self(code) = self;
write!(f, "Bad unicode: {code}")
}
}
/// Converts an [Iterator]
into an
/// [Iterator]
#[derive(Clone, Debug)]
pub struct Chars>(pub I);
impl> Iterator for Chars {
type Item = Result;
fn next(&mut self) -> Option {
let Self(bytes) = self;
let start = bytes.next()? as u32;
let (mut out, count) = match start {
start if start & 0x80 == 0x00 => (start, 0), // ASCII valid range
start if start & 0xe0 == 0xc0 => (start & 0x1f, 1), // 1 continuation byte
start if start & 0xf0 == 0xe0 => (start & 0x0f, 2), // 2 continuation bytes
start if start & 0xf8 == 0xf0 => (start & 0x07, 3), // 3 continuation bytes
_ => return None,
};
for _ in 0..count {
let cont = bytes.next()? as u32;
if cont & 0xc0 != 0x80 {
return None;
}
out = out << 6 | (cont & 0x3f);
}
Some(char::from_u32(out).ok_or(BadUnicode(out)))
}
}
}
pub mod flatten {
//! Flattens an [Iterator] returning [`Result`](Result) or [`Option`](Option)
//! into a *non-[FusedIterator](std::iter::FusedIterator)* over `T`
/// Flattens an [Iterator] returning [`Result`](Result) or [`Option`](Option)
/// into a *non-[FusedIterator](std::iter::FusedIterator)* over `T`
#[derive(Clone, Debug)]
pub struct Flatten>(pub I);
impl>> Iterator for Flatten, I> {
type Item = T;
fn next(&mut self) -> Option {
self.0.next()?.ok()
}
}
impl>> Iterator for Flatten