pub use chars::Chars;
pub use flatten::Flatten;
pub mod 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}")
}
}
#[derive(Clone, Debug)]
pub struct Chars<I: Iterator<Item = u8>>(pub I);
impl<I: Iterator<Item = u8>> Iterator for Chars<I> {
type Item = Result<char, BadUnicode>;
fn next(&mut self) -> Option<Self::Item> {
let Self(bytes) = self;
let start = bytes.next()? as u32;
let (mut out, count) = match start {
start if start & 0x80 == 0x00 => (start, 0), start if start & 0xe0 == 0xc0 => (start & 0x1f, 1), start if start & 0xf0 == 0xe0 => (start & 0x0f, 2), start if start & 0xf8 == 0xf0 => (start & 0x07, 3), _ => 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 {
#[derive(Clone, Debug)]
pub struct Flatten<T, I: Iterator<Item = T>>(pub I);
impl<T, E, I: Iterator<Item = Result<T, E>>> Iterator for Flatten<Result<T, E>, I> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()?.ok()
}
}
impl<T, I: Iterator<Item = Option<T>>> Iterator for Flatten<Option<T>, I> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
self.0.next()?
}
}
}