1use std::borrow::Borrow;
9use std::marker::PhantomData;
10use std::panic::Location;
11
12use crate::error::DecodingProblem::*;
13use crate::Result;
14use crate::helper::{ParseStringEncoding, ProblemLocation};
15
16pub struct Ascii {}
18
19pub struct Decoder<'x, I>
21where
22 I: IntoIterator,
23 I::Item: Borrow<u8> + Sized,
24{
25 iter: <I as IntoIterator>::IntoIter,
26 _marker: PhantomData<&'x ()>,
27}
28
29impl<I> Decoder<'_, I>
30where
31 I: IntoIterator,
32 I::Item: Borrow<u8> + Sized,
33{
34 fn new<'x>(iter: I) -> Decoder<'x, I> {
35 Decoder {
36 iter: iter.into_iter(),
37 _marker: PhantomData,
38 }
39 }
40
41 fn decode_byte(byte: u8) -> Option<char> {
42 match byte {
43 0x00..=0x7f => Some(byte as char),
45 _ => None,
47 }
48 }
49}
50
51impl<I> Iterator for Decoder<'_, I>
52where
53 I: IntoIterator,
54 I::Item: Borrow<u8> + Sized,
55{
56 type Item = Result<char>;
57
58 fn next(&mut self) -> Option<Self::Item> {
59 if let Some(byte) = self.iter.next() {
60 let byte = byte.borrow();
61 Some(match Self::decode_byte(*byte) {
62 Some(c) => Ok(c),
63 None => Err(InvalidByte(*byte, Location::current()).into()),
64 })
65 } else {
66 None
67 }
68 }
69}
70
71impl Ascii {
72 pub fn iter<'iter, I>(iter: I) -> Decoder<'iter, I>
75 where
76 I: IntoIterator,
77 I::Item: Borrow<u8> + Sized,
78 {
79 Decoder::new(iter)
80 }
81
82 pub fn all<I>(iter: I) -> Result<String>
85 where
86 I: IntoIterator,
87 I::Item: Borrow<u8> + Sized,
88 {
89 Self::iter(iter).collect()
90 }
91
92 pub fn first<I>(iter: I) -> Result<String>
95 where
96 I: IntoIterator,
97 I::Item: Borrow<u8> + Sized,
98 {
99 Self::iter(iter)
100 .take_while(|c| match c {
101 Ok(c) => *c != 0 as char,
102 Err(_) => true,
103 })
104 .collect()
105 }
106}
107
108pub trait IteratorExt
111where
112 Self: IntoIterator + Sized,
113 Self::Item: Borrow<u8> + Sized,
114{
115 fn ascii<'b>(self) -> Decoder<'b, Self> { Decoder::new(self) }
117}
118
119impl<I> IteratorExt for I
120where
121 I: IntoIterator,
122 I::Item: Borrow<u8> + Sized,
123{
124}
125
126impl ParseStringEncoding for Ascii {
127 fn parse_str<I>(iter: I) -> Result<String>
128 where
129 I: IntoIterator,
130 I::Item: Borrow<u8> + Sized,
131 {
132 Self::first(iter)
133 }
134}
135
136#[cfg(test)]
141mod tests {
142 use super::*;
143
144 #[test]
145 fn parse_str() {
146 let data = b"abc\0def";
147 assert_eq!(Ascii::parse_str(data).unwrap(), "abc".to_string());
148 }
149}