use std::borrow::Borrow;
use std::marker::PhantomData;
use std::panic::Location;
use crate::error::DecodingProblem::*;
use crate::Result;
use crate::helper::{ParseStringEncoding, ProblemLocation};
pub struct Ascii {}
pub struct Decoder<'x, I>
where
I: IntoIterator,
I::Item: Borrow<u8> + Sized,
{
iter: <I as IntoIterator>::IntoIter,
_marker: PhantomData<&'x ()>,
}
impl<I> Decoder<'_, I>
where
I: IntoIterator,
I::Item: Borrow<u8> + Sized,
{
fn new<'x>(iter: I) -> Decoder<'x, I> {
Decoder {
iter: iter.into_iter(),
_marker: PhantomData,
}
}
fn decode_byte(byte: u8) -> Option<char> {
match byte {
0x00..=0x7f => Some(byte as char),
_ => None,
}
}
}
impl<I> Iterator for Decoder<'_, I>
where
I: IntoIterator,
I::Item: Borrow<u8> + Sized,
{
type Item = Result<char>;
fn next(&mut self) -> Option<Self::Item> {
if let Some(byte) = self.iter.next() {
let byte = byte.borrow();
Some(match Self::decode_byte(*byte) {
Some(c) => Ok(c),
None => Err(InvalidByte(*byte, Location::current()).into()),
})
} else {
None
}
}
}
impl Ascii {
pub fn iter<'iter, I>(iter: I) -> Decoder<'iter, I>
where
I: IntoIterator,
I::Item: Borrow<u8> + Sized,
{
Decoder::new(iter)
}
pub fn all<I>(iter: I) -> Result<String>
where
I: IntoIterator,
I::Item: Borrow<u8> + Sized,
{
Self::iter(iter).collect()
}
pub fn first<I>(iter: I) -> Result<String>
where
I: IntoIterator,
I::Item: Borrow<u8> + Sized,
{
Self::iter(iter)
.take_while(|c| match c {
Ok(c) => *c != 0 as char,
Err(_) => true,
})
.collect()
}
}
pub trait IteratorExt
where
Self: IntoIterator + Sized,
Self::Item: Borrow<u8> + Sized,
{
fn ascii<'b>(self) -> Decoder<'b, Self> { Decoder::new(self) }
}
impl<I> IteratorExt for I
where
I: IntoIterator,
I::Item: Borrow<u8> + Sized,
{
}
impl ParseStringEncoding for Ascii {
fn parse_str<I>(iter: I) -> Result<String>
where
I: IntoIterator,
I::Item: Borrow<u8> + Sized,
{
Self::first(iter)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_str() {
let data = b"abc\0def";
assert_eq!(Ascii::parse_str(data).unwrap(), "abc".to_string());
}
}