hex_conservative/
iter.rs

1// SPDX-License-Identifier: CC0-1.0
2
3//! Iterator that converts hex to bytes.
4
5use core::iter::FusedIterator;
6use core::str;
7#[cfg(feature = "std")]
8use std::io;
9
10#[cfg(all(feature = "core2", not(feature = "std")))]
11use core2::io;
12
13use crate::parse::HexToBytesError;
14
15/// Iterator over a hex-encoded string slice which decodes hex and yields bytes.
16pub struct HexToBytesIter<'a> {
17    /// The [`Bytes`] iterator whose next two bytes will be decoded to yield the next byte.
18    ///
19    /// # Invariants
20    ///
21    /// `iter` is guaranteed to be of even length.
22    ///
23    /// [`Bytes`]: core::str::Bytes
24    iter: str::Bytes<'a>,
25}
26
27impl<'a> HexToBytesIter<'a> {
28    /// Constructs a new `HexToBytesIter` from a string slice.
29    ///
30    /// # Errors
31    ///
32    /// If the input string is of odd length.
33    pub fn new(s: &'a str) -> Result<HexToBytesIter<'a>, HexToBytesError> {
34        if s.len() % 2 != 0 {
35            Err(HexToBytesError::OddLengthString(s.len()))
36        } else {
37            Ok(HexToBytesIter { iter: s.bytes() })
38        }
39    }
40}
41
42impl<'a> Iterator for HexToBytesIter<'a> {
43    type Item = Result<u8, HexToBytesError>;
44
45    fn next(&mut self) -> Option<Result<u8, HexToBytesError>> {
46        let hi = self.iter.next()?;
47        let lo = self.iter.next().expect("iter length invariant violated, this is a bug");
48        Some(hex_chars_to_byte(hi, lo))
49    }
50
51    fn size_hint(&self) -> (usize, Option<usize>) {
52        let (min, max) = self.iter.size_hint();
53        (min / 2, max.map(|x| x / 2))
54    }
55}
56
57impl<'a> DoubleEndedIterator for HexToBytesIter<'a> {
58    fn next_back(&mut self) -> Option<Result<u8, HexToBytesError>> {
59        let lo = self.iter.next_back()?;
60        let hi = self.iter.next_back().expect("iter length invariant violated, this is a bug");
61        Some(hex_chars_to_byte(hi, lo))
62    }
63}
64
65impl<'a> ExactSizeIterator for HexToBytesIter<'a> {
66    fn len(&self) -> usize { self.iter.len() / 2 }
67}
68
69impl<'a> FusedIterator for HexToBytesIter<'a> {}
70
71#[cfg(any(feature = "std", feature = "core2"))]
72impl<'a> io::Read for HexToBytesIter<'a> {
73    fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
74        let mut bytes_read = 0usize;
75        for dst in buf {
76            match self.next() {
77                Some(Ok(src)) => {
78                    *dst = src;
79                    bytes_read += 1;
80                }
81                _ => break,
82            }
83        }
84        Ok(bytes_read)
85    }
86}
87
88/// `hi` and `lo` are bytes representing hex characters.
89fn hex_chars_to_byte(hi: u8, lo: u8) -> Result<u8, HexToBytesError> {
90    let hih = (hi as char).to_digit(16).ok_or(HexToBytesError::InvalidChar(hi))?;
91    let loh = (lo as char).to_digit(16).ok_or(HexToBytesError::InvalidChar(lo))?;
92
93    let ret = (hih << 4) + loh;
94    Ok(ret as u8)
95}
96
97/// Iterator over bytes which encodes the bytes and yields hex characters.
98pub struct BytesToHexIter<I: Iterator<Item = u8>> {
99    /// The iterator whose next byte will be encoded to yield hex characters.
100    iter: I,
101    /// The low character of the pair (high, low) of hex characters encoded per byte.
102    low: Option<char>,
103}
104
105impl<I> BytesToHexIter<I>
106where
107    I: Iterator<Item = u8>,
108{
109    /// Constructs a new `BytesToHexIter` from a byte iterator.
110    pub fn new(iter: I) -> BytesToHexIter<I> { Self { iter, low: None } }
111}
112
113impl<I> Iterator for BytesToHexIter<I>
114where
115    I: Iterator<Item = u8>,
116{
117    type Item = char;
118
119    fn next(&mut self) -> Option<char> {
120        match self.low {
121            Some(c) => {
122                self.low = None;
123                Some(c)
124            }
125            None => self.iter.next().map(|b| {
126                let (high, low) = byte_to_hex_chars(b);
127                self.low = Some(low);
128                high
129            }),
130        }
131    }
132
133    fn size_hint(&self) -> (usize, Option<usize>) {
134        let (min, max) = self.iter.size_hint();
135        match self.low {
136            Some(_) => (min * 2 + 1, max.map(|max| max * 2 + 1)),
137            None => (min * 2, max.map(|max| max * 2)),
138        }
139    }
140}
141
142impl<I> DoubleEndedIterator for BytesToHexIter<I>
143where
144    I: DoubleEndedIterator + Iterator<Item = u8>,
145{
146    fn next_back(&mut self) -> Option<char> {
147        match self.low {
148            Some(c) => {
149                self.low = None;
150                Some(c)
151            }
152            None => self.iter.next_back().map(|b| {
153                let (high, low) = byte_to_hex_chars(b);
154                self.low = Some(low);
155                high
156            }),
157        }
158    }
159}
160
161impl<I> ExactSizeIterator for BytesToHexIter<I>
162where
163    I: ExactSizeIterator + Iterator<Item = u8>,
164{
165    fn len(&self) -> usize { self.iter.len() * 2 }
166}
167
168impl<I> FusedIterator for BytesToHexIter<I> where I: FusedIterator + Iterator<Item = u8> {}
169
170/// Returns the (high, low) hex characters encoding `b`.
171fn byte_to_hex_chars(b: u8) -> (char, char) {
172    const HEX_TABLE: [u8; 16] = *b"0123456789abcdef";
173
174    let high = HEX_TABLE[usize::from(b >> 4)];
175    let low = HEX_TABLE[usize::from(b & 0b00001111)];
176
177    (char::from(high), char::from(low))
178}
179
180#[cfg(test)]
181mod tests {
182    use super::*;
183
184    #[test]
185    fn encode_byte() {
186        let tcs =
187            vec![(0x00, ('0', '0')), (0x0a, ('0', 'a')), (0xad, ('a', 'd')), (0xff, ('f', 'f'))];
188        for (b, (high, low)) in tcs {
189            assert_eq!(byte_to_hex_chars(b), (high, low));
190        }
191        assert_eq!(byte_to_hex_chars(0x00), ('0', '0'));
192        assert_eq!(byte_to_hex_chars(0x0a), ('0', 'a'));
193        assert_eq!(byte_to_hex_chars(0xad), ('a', 'd'));
194        assert_eq!(byte_to_hex_chars(0xff), ('f', 'f'));
195    }
196
197    #[test]
198    fn decode_iter_forward() {
199        let hex = "deadbeef";
200        let v = vec![0xde, 0xad, 0xbe, 0xef];
201
202        for (i, b) in HexToBytesIter::new(hex).unwrap().enumerate() {
203            assert_eq!(b.unwrap(), v[i]);
204        }
205    }
206
207    #[test]
208    fn decode_iter_backward() {
209        let hex = "deadbeef";
210        let v = vec![0xef, 0xbe, 0xad, 0xde];
211
212        for (i, b) in HexToBytesIter::new(hex).unwrap().rev().enumerate() {
213            assert_eq!(b.unwrap(), v[i]);
214        }
215    }
216
217    #[test]
218    fn encode_iter() {
219        let v = vec![0xde, 0xad, 0xbe, 0xef];
220        let hex = "deadbeef";
221
222        for (i, c) in BytesToHexIter::new(v.iter().cloned()).enumerate() {
223            assert_eq!(c, hex.chars().nth(i).unwrap());
224        }
225    }
226
227    #[test]
228    fn encode_iter_backwards() {
229        let v = vec![0xde, 0xad, 0xbe, 0xef];
230        let hex = "efbeadde";
231
232        for (i, c) in BytesToHexIter::new(v.iter().cloned()).rev().enumerate() {
233            assert_eq!(c, hex.chars().nth(i).unwrap());
234        }
235    }
236
237    #[test]
238    fn roundtrip_forward() {
239        let hex = "deadbeefcafebabe";
240        let bytes_iter = HexToBytesIter::new(hex).unwrap().map(|res| res.unwrap());
241        let got = BytesToHexIter::new(bytes_iter).collect::<String>();
242        assert_eq!(got, hex);
243    }
244
245    #[test]
246    fn roundtrip_backward() {
247        let hex = "deadbeefcafebabe";
248        let bytes_iter = HexToBytesIter::new(hex).unwrap().rev().map(|res| res.unwrap());
249        let got = BytesToHexIter::new(bytes_iter).rev().collect::<String>();
250        assert_eq!(got, hex);
251    }
252}