1use core::convert::TryInto;
6use core::iter::FusedIterator;
7use core::str;
8#[cfg(feature = "std")]
9use std::io;
10
11#[cfg(all(feature = "core2", not(feature = "std")))]
12use core2::io;
13
14use crate::error::{InvalidCharError, OddLengthStringError};
15
16pub type HexSliceToBytesIter<'a> = HexToBytesIter<HexDigitsIter<'a>>;
18
19pub struct HexToBytesIter<T: Iterator<Item = [u8; 2]>> {
21 iter: T,
22}
23
24impl<'a> HexToBytesIter<HexDigitsIter<'a>> {
25 #[inline]
31 pub fn new(s: &'a str) -> Result<Self, OddLengthStringError> {
32 if s.len() % 2 != 0 {
33 Err(OddLengthStringError { len: s.len() })
34 } else {
35 Ok(Self::new_unchecked(s))
36 }
37 }
38
39 pub(crate) fn new_unchecked(s: &'a str) -> Self {
40 Self::from_pairs(HexDigitsIter::new_unchecked(s.as_bytes()))
41 }
42}
43
44impl<T: Iterator<Item = [u8; 2]>> HexToBytesIter<T> {
45 #[inline]
47 pub fn from_pairs(iter: T) -> Self { Self { iter } }
48}
49
50impl<T: Iterator<Item = [u8; 2]>> Iterator for HexToBytesIter<T> {
51 type Item = Result<u8, InvalidCharError>;
52
53 #[inline]
54 fn next(&mut self) -> Option<Self::Item> {
55 let [hi, lo] = self.iter.next()?;
56 Some(hex_chars_to_byte(hi, lo))
57 }
58
59 #[inline]
60 fn size_hint(&self) -> (usize, Option<usize>) {
61 let (min, max) = self.iter.size_hint();
62 (min / 2, max.map(|x| x / 2))
63 }
64
65 #[inline]
66 fn nth(&mut self, n: usize) -> Option<Self::Item> {
67 let [hi, lo] = self.iter.nth(n)?;
68 Some(hex_chars_to_byte(hi, lo))
69 }
70}
71
72impl<T: Iterator<Item = [u8; 2]> + DoubleEndedIterator> DoubleEndedIterator for HexToBytesIter<T> {
73 #[inline]
74 fn next_back(&mut self) -> Option<Self::Item> {
75 let [hi, lo] = self.iter.next_back()?;
76 Some(hex_chars_to_byte(hi, lo))
77 }
78
79 #[inline]
80 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
81 let [hi, lo] = self.iter.nth_back(n)?;
82 Some(hex_chars_to_byte(hi, lo))
83 }
84}
85
86impl<T: Iterator<Item = [u8; 2]> + ExactSizeIterator> ExactSizeIterator for HexToBytesIter<T> {}
87
88impl<T: Iterator<Item = [u8; 2]> + FusedIterator> FusedIterator for HexToBytesIter<T> {}
89
90#[cfg(any(feature = "std", feature = "core2"))]
91impl<T: Iterator<Item = [u8; 2]> + FusedIterator> io::Read for HexToBytesIter<T> {
92 #[inline]
93 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
94 let mut bytes_read = 0usize;
95 for dst in buf {
96 match self.next() {
97 Some(Ok(src)) => {
98 *dst = src;
99 bytes_read += 1;
100 }
101 _ => break,
102 }
103 }
104 Ok(bytes_read)
105 }
106}
107
108pub struct HexDigitsIter<'a> {
114 iter: core::slice::ChunksExact<'a, u8>,
118}
119
120impl<'a> HexDigitsIter<'a> {
121 #[inline]
122 fn new_unchecked(digits: &'a [u8]) -> Self { Self { iter: digits.chunks_exact(2) } }
123}
124
125impl<'a> Iterator for HexDigitsIter<'a> {
126 type Item = [u8; 2];
127
128 #[inline]
129 fn next(&mut self) -> Option<Self::Item> {
130 self.iter.next().map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
131 }
132
133 #[inline]
134 fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
135
136 #[inline]
137 fn nth(&mut self, n: usize) -> Option<Self::Item> {
138 self.iter.nth(n).map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
139 }
140}
141
142impl<'a> DoubleEndedIterator for HexDigitsIter<'a> {
143 #[inline]
144 fn next_back(&mut self) -> Option<Self::Item> {
145 self.iter.next_back().map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
146 }
147
148 #[inline]
149 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
150 self.iter.nth_back(n).map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
151 }
152}
153
154impl<'a> ExactSizeIterator for HexDigitsIter<'a> {}
155
156impl<'a> core::iter::FusedIterator for HexDigitsIter<'a> {}
157
158fn hex_chars_to_byte(hi: u8, lo: u8) -> Result<u8, InvalidCharError> {
160 let hih = (hi as char).to_digit(16).ok_or(InvalidCharError { invalid: hi })?;
161 let loh = (lo as char).to_digit(16).ok_or(InvalidCharError { invalid: lo })?;
162
163 let ret = (hih << 4) + loh;
164 Ok(ret as u8)
165}
166
167pub struct BytesToHexIter<I: Iterator<Item = u8>> {
169 iter: I,
171 low: Option<char>,
173}
174
175impl<I> BytesToHexIter<I>
176where
177 I: Iterator<Item = u8>,
178{
179 pub fn new(iter: I) -> BytesToHexIter<I> { Self { iter, low: None } }
181}
182
183impl<I> Iterator for BytesToHexIter<I>
184where
185 I: Iterator<Item = u8>,
186{
187 type Item = char;
188
189 #[inline]
190 fn next(&mut self) -> Option<char> {
191 match self.low {
192 Some(c) => {
193 self.low = None;
194 Some(c)
195 }
196 None => self.iter.next().map(|b| {
197 let (high, low) = byte_to_hex_chars(b);
198 self.low = Some(low);
199 high
200 }),
201 }
202 }
203
204 #[inline]
205 fn size_hint(&self) -> (usize, Option<usize>) {
206 let (min, max) = self.iter.size_hint();
207 match self.low {
208 Some(_) => (min * 2 + 1, max.map(|max| max * 2 + 1)),
209 None => (min * 2, max.map(|max| max * 2)),
210 }
211 }
212}
213
214impl<I> DoubleEndedIterator for BytesToHexIter<I>
215where
216 I: DoubleEndedIterator + Iterator<Item = u8>,
217{
218 #[inline]
219 fn next_back(&mut self) -> Option<char> {
220 match self.low {
221 Some(c) => {
222 self.low = None;
223 Some(c)
224 }
225 None => self.iter.next_back().map(|b| {
226 let (high, low) = byte_to_hex_chars(b);
227 self.low = Some(low);
228 high
229 }),
230 }
231 }
232}
233
234impl<I> ExactSizeIterator for BytesToHexIter<I>
235where
236 I: ExactSizeIterator + Iterator<Item = u8>,
237{
238 #[inline]
239 fn len(&self) -> usize { self.iter.len() * 2 }
240}
241
242impl<I> FusedIterator for BytesToHexIter<I> where I: FusedIterator + Iterator<Item = u8> {}
243
244fn byte_to_hex_chars(b: u8) -> (char, char) {
246 const HEX_TABLE: [u8; 16] = *b"0123456789abcdef";
247
248 let high = HEX_TABLE[usize::from(b >> 4)];
249 let low = HEX_TABLE[usize::from(b & 0b00001111)];
250
251 (char::from(high), char::from(low))
252}
253
254#[cfg(test)]
255mod tests {
256 use super::*;
257
258 #[test]
259 fn encode_byte() {
260 let tcs =
261 vec![(0x00, ('0', '0')), (0x0a, ('0', 'a')), (0xad, ('a', 'd')), (0xff, ('f', 'f'))];
262 for (b, (high, low)) in tcs {
263 assert_eq!(byte_to_hex_chars(b), (high, low));
264 }
265 assert_eq!(byte_to_hex_chars(0x00), ('0', '0'));
266 assert_eq!(byte_to_hex_chars(0x0a), ('0', 'a'));
267 assert_eq!(byte_to_hex_chars(0xad), ('a', 'd'));
268 assert_eq!(byte_to_hex_chars(0xff), ('f', 'f'));
269 }
270
271 #[test]
272 fn decode_iter_forward() {
273 let hex = "deadbeef";
274 let bytes = [0xde, 0xad, 0xbe, 0xef];
275
276 for (i, b) in HexToBytesIter::new(hex).unwrap().enumerate() {
277 assert_eq!(b.unwrap(), bytes[i]);
278 }
279 }
280
281 #[test]
282 fn decode_iter_backward() {
283 let hex = "deadbeef";
284 let bytes = [0xef, 0xbe, 0xad, 0xde];
285
286 for (i, b) in HexToBytesIter::new(hex).unwrap().rev().enumerate() {
287 assert_eq!(b.unwrap(), bytes[i]);
288 }
289 }
290
291 #[test]
292 fn encode_iter() {
293 let bytes = [0xde, 0xad, 0xbe, 0xef];
294 let hex = "deadbeef";
295
296 for (i, c) in BytesToHexIter::new(bytes.iter().cloned()).enumerate() {
297 assert_eq!(c, hex.chars().nth(i).unwrap());
298 }
299 }
300
301 #[test]
302 fn encode_iter_backwards() {
303 let bytes = [0xde, 0xad, 0xbe, 0xef];
304 let hex = "efbeadde";
305
306 for (i, c) in BytesToHexIter::new(bytes.iter().cloned()).rev().enumerate() {
307 assert_eq!(c, hex.chars().nth(i).unwrap());
308 }
309 }
310
311 #[test]
312 fn roundtrip_forward() {
313 let hex = "deadbeefcafebabe";
314 let bytes_iter = HexToBytesIter::new(hex).unwrap().map(|res| res.unwrap());
315 let got = BytesToHexIter::new(bytes_iter).collect::<String>();
316 assert_eq!(got, hex);
317 }
318
319 #[test]
320 fn roundtrip_backward() {
321 let hex = "deadbeefcafebabe";
322 let bytes_iter = HexToBytesIter::new(hex).unwrap().rev().map(|res| res.unwrap());
323 let got = BytesToHexIter::new(bytes_iter).rev().collect::<String>();
324 assert_eq!(got, hex);
325 }
326}