69 lines
2.6 KiB
Rust
69 lines
2.6 KiB
Rust
|
//! Shmancy iterator adapters
|
||
|
|
||
|
pub use chars::Chars;
|
||
|
pub use flatten::Flatten;
|
||
|
|
||
|
pub mod chars {
|
||
|
//! Converts an <code>[Iterator]<Item = [u8]></code> into an
|
||
|
//! <code>[Iterator]<Item = [Result]<[char], [BadUnicode]>></code>
|
||
|
|
||
|
/// 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 <code>[Iterator]<Item = [u8]></code> into an
|
||
|
/// <code>[Iterator]<Item = [char]></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), // 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<T, E>`](Result) or [`Option<T>`](Option)
|
||
|
//! into a *non-[FusedIterator](std::iter::FusedIterator)* over `T`
|
||
|
|
||
|
/// Flattens an [Iterator] returning [`Result<T, E>`](Result) or [`Option<T>`](Option)
|
||
|
/// into a *non-[FusedIterator](std::iter::FusedIterator)* over `T`
|
||
|
#[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()?
|
||
|
}
|
||
|
}
|
||
|
}
|