1use core::borrow::Borrow;
6use core::convert::TryInto;
7use core::iter::FusedIterator;
8use core::str;
9#[cfg(feature = "std")]
10use std::io;
11
12#[cfg(all(feature = "alloc", not(feature = "std")))]
13use crate::alloc::vec::Vec;
14use crate::error::{InvalidCharError, OddLengthStringError};
15use crate::{Case, Table};
16
17pub type HexSliceToBytesIter<'a> = HexToBytesIter<HexDigitsIter<'a>>;
19
20pub struct HexToBytesIter<T: Iterator<Item = [u8; 2]>> {
22 iter: T,
23 original_len: usize,
24}
25
26impl<'a> HexToBytesIter<HexDigitsIter<'a>> {
27 #[inline]
33 pub fn new(s: &'a str) -> Result<Self, OddLengthStringError> {
34 if s.len() % 2 != 0 {
35 Err(OddLengthStringError { len: s.len() })
36 } else {
37 Ok(Self::new_unchecked(s))
38 }
39 }
40
41 pub(crate) fn new_unchecked(s: &'a str) -> Self {
42 Self::from_pairs(HexDigitsIter::new_unchecked(s.as_bytes()))
43 }
44
45 pub(crate) fn drain_to_slice(self, buf: &mut [u8]) -> Result<(), InvalidCharError> {
54 assert_eq!(self.len(), buf.len());
55 let mut ptr = buf.as_mut_ptr();
56 for byte in self {
57 unsafe {
59 core::ptr::write(ptr, byte?);
60 ptr = ptr.add(1);
61 }
62 }
63 Ok(())
64 }
65
66 #[cfg(any(test, feature = "std", feature = "alloc"))]
71 pub(crate) fn drain_to_vec(self) -> Result<Vec<u8>, InvalidCharError> {
72 let len = self.len();
73 let mut ret = Vec::with_capacity(len);
74 let mut ptr = ret.as_mut_ptr();
75 for byte in self {
76 unsafe {
78 core::ptr::write(ptr, byte?);
80 ptr = ptr.add(1);
81 }
82 }
83 unsafe {
85 ret.set_len(len);
86 }
87 Ok(ret)
88 }
89}
90
91impl<T: Iterator<Item = [u8; 2]> + ExactSizeIterator> HexToBytesIter<T> {
92 #[inline]
94 pub fn from_pairs(iter: T) -> Self { Self { original_len: iter.len(), iter } }
95}
96
97impl<T: Iterator<Item = [u8; 2]> + ExactSizeIterator> Iterator for HexToBytesIter<T> {
98 type Item = Result<u8, InvalidCharError>;
99
100 #[inline]
101 fn next(&mut self) -> Option<Self::Item> {
102 let [hi, lo] = self.iter.next()?;
103 Some(hex_chars_to_byte(hi, lo).map_err(|(c, is_high)| InvalidCharError {
104 invalid: c,
105 pos: if is_high {
106 (self.original_len - self.iter.len() - 1) * 2
107 } else {
108 (self.original_len - self.iter.len() - 1) * 2 + 1
109 },
110 }))
111 }
112
113 #[inline]
114 fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
115
116 #[inline]
117 fn nth(&mut self, n: usize) -> Option<Self::Item> {
118 let [hi, lo] = self.iter.nth(n)?;
119 Some(hex_chars_to_byte(hi, lo).map_err(|(c, is_high)| InvalidCharError {
120 invalid: c,
121 pos: if is_high {
122 (self.original_len - self.iter.len() - 1) * 2
123 } else {
124 (self.original_len - self.iter.len() - 1) * 2 + 1
125 },
126 }))
127 }
128}
129
130impl<T: Iterator<Item = [u8; 2]> + DoubleEndedIterator + ExactSizeIterator> DoubleEndedIterator
131 for HexToBytesIter<T>
132{
133 #[inline]
134 fn next_back(&mut self) -> Option<Self::Item> {
135 let [hi, lo] = self.iter.next_back()?;
136 Some(hex_chars_to_byte(hi, lo).map_err(|(c, is_high)| InvalidCharError {
137 invalid: c,
138 pos: if is_high { self.iter.len() * 2 } else { self.iter.len() * 2 + 1 },
139 }))
140 }
141
142 #[inline]
143 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
144 let [hi, lo] = self.iter.nth_back(n)?;
145 Some(hex_chars_to_byte(hi, lo).map_err(|(c, is_high)| InvalidCharError {
146 invalid: c,
147 pos: if is_high { self.iter.len() * 2 } else { self.iter.len() * 2 + 1 },
148 }))
149 }
150}
151
152impl<T: Iterator<Item = [u8; 2]> + ExactSizeIterator> ExactSizeIterator for HexToBytesIter<T> {}
153
154impl<T: Iterator<Item = [u8; 2]> + ExactSizeIterator + FusedIterator> FusedIterator
155 for HexToBytesIter<T>
156{
157}
158
159#[cfg(feature = "std")]
160impl<T: Iterator<Item = [u8; 2]> + ExactSizeIterator + FusedIterator> io::Read
161 for HexToBytesIter<T>
162{
163 #[inline]
164 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
165 let mut bytes_read = 0usize;
166 for dst in buf {
167 match self.next() {
168 Some(Ok(src)) => {
169 *dst = src;
170 bytes_read += 1;
171 }
172 _ => break,
173 }
174 }
175 Ok(bytes_read)
176 }
177}
178
179pub struct HexDigitsIter<'a> {
185 iter: core::slice::ChunksExact<'a, u8>,
189}
190
191impl<'a> HexDigitsIter<'a> {
192 #[inline]
193 fn new_unchecked(digits: &'a [u8]) -> Self { Self { iter: digits.chunks_exact(2) } }
194}
195
196impl<'a> Iterator for HexDigitsIter<'a> {
197 type Item = [u8; 2];
198
199 #[inline]
200 fn next(&mut self) -> Option<Self::Item> {
201 self.iter.next().map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
202 }
203
204 #[inline]
205 fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
206
207 #[inline]
208 fn nth(&mut self, n: usize) -> Option<Self::Item> {
209 self.iter.nth(n).map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
210 }
211}
212
213impl<'a> DoubleEndedIterator for HexDigitsIter<'a> {
214 #[inline]
215 fn next_back(&mut self) -> Option<Self::Item> {
216 self.iter.next_back().map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
217 }
218
219 #[inline]
220 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
221 self.iter.nth_back(n).map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
222 }
223}
224
225impl<'a> ExactSizeIterator for HexDigitsIter<'a> {}
226
227impl<'a> core::iter::FusedIterator for HexDigitsIter<'a> {}
228
229fn hex_chars_to_byte(hi: u8, lo: u8) -> Result<u8, (u8, bool)> {
233 let hih = (hi as char).to_digit(16).ok_or((hi, true))?;
234 let loh = (lo as char).to_digit(16).ok_or((lo, false))?;
235
236 let ret = (hih << 4) + loh;
237 Ok(ret as u8)
238}
239
240pub struct BytesToHexIter<I>
242where
243 I: Iterator,
244 I::Item: Borrow<u8>,
245{
246 iter: I,
248 low: Option<char>,
250 table: &'static Table,
252}
253
254impl<I> BytesToHexIter<I>
255where
256 I: Iterator,
257 I::Item: Borrow<u8>,
258{
259 pub fn new(iter: I, case: Case) -> BytesToHexIter<I> {
262 Self { iter, low: None, table: case.table() }
263 }
264}
265
266impl<I> Iterator for BytesToHexIter<I>
267where
268 I: Iterator,
269 I::Item: Borrow<u8>,
270{
271 type Item = char;
272
273 #[inline]
274 fn next(&mut self) -> Option<char> {
275 match self.low {
276 Some(c) => {
277 self.low = None;
278 Some(c)
279 }
280 None => self.iter.next().map(|b| {
281 let [high, low] = self.table.byte_to_chars(*b.borrow());
282 self.low = Some(low);
283 high
284 }),
285 }
286 }
287
288 #[inline]
289 fn size_hint(&self) -> (usize, Option<usize>) {
290 let (min, max) = self.iter.size_hint();
291 match self.low {
292 Some(_) => (min * 2 + 1, max.map(|max| max * 2 + 1)),
293 None => (min * 2, max.map(|max| max * 2)),
294 }
295 }
296}
297
298impl<I> DoubleEndedIterator for BytesToHexIter<I>
299where
300 I: DoubleEndedIterator,
301 I::Item: Borrow<u8>,
302{
303 #[inline]
304 fn next_back(&mut self) -> Option<char> {
305 match self.low {
306 Some(c) => {
307 self.low = None;
308 Some(c)
309 }
310 None => self.iter.next_back().map(|b| {
311 let [high, low] = self.table.byte_to_chars(*b.borrow());
312 self.low = Some(low);
313 high
314 }),
315 }
316 }
317}
318
319impl<I> ExactSizeIterator for BytesToHexIter<I>
320where
321 I: ExactSizeIterator,
322 I::Item: Borrow<u8>,
323{
324 #[inline]
325 fn len(&self) -> usize { self.iter.len() * 2 }
326}
327
328impl<I> FusedIterator for BytesToHexIter<I>
329where
330 I: FusedIterator,
331 I::Item: Borrow<u8>,
332{
333}
334
335#[cfg(test)]
336mod tests {
337 use super::*;
338
339 #[test]
340 fn encode_byte() {
341 assert_eq!(Table::LOWER.byte_to_chars(0x00), ['0', '0']);
342 assert_eq!(Table::LOWER.byte_to_chars(0x0a), ['0', 'a']);
343 assert_eq!(Table::LOWER.byte_to_chars(0xad), ['a', 'd']);
344 assert_eq!(Table::LOWER.byte_to_chars(0xff), ['f', 'f']);
345
346 assert_eq!(Table::UPPER.byte_to_chars(0x00), ['0', '0']);
347 assert_eq!(Table::UPPER.byte_to_chars(0x0a), ['0', 'A']);
348 assert_eq!(Table::UPPER.byte_to_chars(0xad), ['A', 'D']);
349 assert_eq!(Table::UPPER.byte_to_chars(0xff), ['F', 'F']);
350
351 let mut buf = [0u8; 2];
352 assert_eq!(Table::LOWER.byte_to_str(&mut buf, 0x00), "00");
353 assert_eq!(Table::LOWER.byte_to_str(&mut buf, 0x0a), "0a");
354 assert_eq!(Table::LOWER.byte_to_str(&mut buf, 0xad), "ad");
355 assert_eq!(Table::LOWER.byte_to_str(&mut buf, 0xff), "ff");
356
357 assert_eq!(Table::UPPER.byte_to_str(&mut buf, 0x00), "00");
358 assert_eq!(Table::UPPER.byte_to_str(&mut buf, 0x0a), "0A");
359 assert_eq!(Table::UPPER.byte_to_str(&mut buf, 0xad), "AD");
360 assert_eq!(Table::UPPER.byte_to_str(&mut buf, 0xff), "FF");
361 }
362
363 #[test]
364 fn decode_iter_forward() {
365 let hex = "deadbeef";
366 let bytes = [0xde, 0xad, 0xbe, 0xef];
367
368 for (i, b) in HexToBytesIter::new(hex).unwrap().enumerate() {
369 assert_eq!(b.unwrap(), bytes[i]);
370 }
371
372 let mut iter = HexToBytesIter::new(hex).unwrap();
373 for i in (0..=bytes.len()).rev() {
374 assert_eq!(iter.len(), i);
375 let _ = iter.next();
376 }
377 }
378
379 #[test]
380 fn decode_iter_backward() {
381 let hex = "deadbeef";
382 let bytes = [0xef, 0xbe, 0xad, 0xde];
383
384 for (i, b) in HexToBytesIter::new(hex).unwrap().rev().enumerate() {
385 assert_eq!(b.unwrap(), bytes[i]);
386 }
387
388 let mut iter = HexToBytesIter::new(hex).unwrap().rev();
389 for i in (0..=bytes.len()).rev() {
390 assert_eq!(iter.len(), i);
391 let _ = iter.next();
392 }
393 }
394
395 #[test]
396 fn hex_to_digits_size_hint() {
397 let hex = "deadbeef";
398 let iter = HexDigitsIter::new_unchecked(hex.as_bytes());
399 assert_eq!(iter.size_hint(), (4, Some(4)));
401 }
402
403 #[test]
404 fn hex_to_bytes_size_hint() {
405 let hex = "deadbeef";
406 let iter = HexToBytesIter::new_unchecked(hex);
407 assert_eq!(iter.size_hint(), (4, Some(4)));
408 }
409
410 #[test]
411 fn hex_to_bytes_slice_drain() {
412 let hex = "deadbeef";
413 let want = [0xde, 0xad, 0xbe, 0xef];
414 let iter = HexToBytesIter::new_unchecked(hex);
415 let mut got = [0u8; 4];
416 iter.drain_to_slice(&mut got).unwrap();
417 assert_eq!(got, want);
418
419 let hex = "";
420 let want = [];
421 let iter = HexToBytesIter::new_unchecked(hex);
422 let mut got = [];
423 iter.drain_to_slice(&mut got).unwrap();
424 assert_eq!(got, want);
425 }
426
427 #[test]
428 #[should_panic]
429 fn hex_to_bytes_slice_drain_panic_empty() {
430 let hex = "deadbeef";
431 let iter = HexToBytesIter::new_unchecked(hex);
432 let mut got = [];
433 iter.drain_to_slice(&mut got).unwrap();
434 }
435
436 #[test]
437 #[should_panic]
438 fn hex_to_bytes_slice_drain_panic_too_small() {
439 let hex = "deadbeef";
440 let iter = HexToBytesIter::new_unchecked(hex);
441 let mut got = [0u8; 3];
442 iter.drain_to_slice(&mut got).unwrap();
443 }
444
445 #[test]
446 #[should_panic]
447 fn hex_to_bytes_slice_drain_panic_too_big() {
448 let hex = "deadbeef";
449 let iter = HexToBytesIter::new_unchecked(hex);
450 let mut got = [0u8; 5];
451 iter.drain_to_slice(&mut got).unwrap();
452 }
453
454 #[test]
455 fn hex_to_bytes_slice_drain_first_char_error() {
456 let hex = "geadbeef";
457 let iter = HexToBytesIter::new_unchecked(hex);
458 let mut got = [0u8; 4];
459 assert_eq!(iter.drain_to_slice(&mut got), Err(InvalidCharError { invalid: b'g', pos: 0 }));
460 }
461
462 #[test]
463 fn hex_to_bytes_slice_drain_middle_char_error() {
464 let hex = "deadgeef";
465 let iter = HexToBytesIter::new_unchecked(hex);
466 let mut got = [0u8; 4];
467 assert_eq!(iter.drain_to_slice(&mut got), Err(InvalidCharError { invalid: b'g', pos: 4 }));
468 }
469
470 #[test]
471 fn hex_to_bytes_slice_drain_end_char_error() {
472 let hex = "deadbeeg";
473 let iter = HexToBytesIter::new_unchecked(hex);
474 let mut got = [0u8; 4];
475 assert_eq!(iter.drain_to_slice(&mut got), Err(InvalidCharError { invalid: b'g', pos: 7 }));
476 }
477
478 #[test]
479 fn hex_to_bytes_vec_drain() {
480 let hex = "deadbeef";
481 let want = [0xde, 0xad, 0xbe, 0xef];
482 let iter = HexToBytesIter::new_unchecked(hex);
483 let got = iter.drain_to_vec().unwrap();
484 assert_eq!(got, want);
485
486 let hex = "";
487 let iter = HexToBytesIter::new_unchecked(hex);
488 let got = iter.drain_to_vec().unwrap();
489 assert!(got.is_empty());
490 }
491
492 #[test]
493 fn hex_to_bytes_vec_drain_first_char_error() {
494 let hex = "geadbeef";
495 let iter = HexToBytesIter::new_unchecked(hex);
496 assert_eq!(iter.drain_to_vec(), Err(InvalidCharError { invalid: b'g', pos: 0 }));
497 }
498
499 #[test]
500 fn hex_to_bytes_vec_drain_middle_char_error() {
501 let hex = "deadgeef";
502 let iter = HexToBytesIter::new_unchecked(hex);
503 assert_eq!(iter.drain_to_vec(), Err(InvalidCharError { invalid: b'g', pos: 4 }));
504 }
505
506 #[test]
507 fn hex_to_bytes_vec_drain_end_char_error() {
508 let hex = "deadbeeg";
509 let iter = HexToBytesIter::new_unchecked(hex);
510 assert_eq!(iter.drain_to_vec(), Err(InvalidCharError { invalid: b'g', pos: 7 }));
511 }
512
513 #[test]
514 fn encode_iter() {
515 let bytes = [0xde, 0xad, 0xbe, 0xef];
516 let lower_want = "deadbeef";
517 let upper_want = "DEADBEEF";
518
519 for (i, c) in BytesToHexIter::new(bytes.iter(), Case::Lower).enumerate() {
520 assert_eq!(c, lower_want.chars().nth(i).unwrap());
521 }
522 for (i, c) in BytesToHexIter::new(bytes.iter(), Case::Upper).enumerate() {
523 assert_eq!(c, upper_want.chars().nth(i).unwrap());
524 }
525 }
526
527 #[test]
528 fn encode_iter_backwards() {
529 let bytes = [0xde, 0xad, 0xbe, 0xef];
530 let lower_want = "efbeadde";
531 let upper_want = "EFBEADDE";
532
533 for (i, c) in BytesToHexIter::new(bytes.iter(), Case::Lower).rev().enumerate() {
534 assert_eq!(c, lower_want.chars().nth(i).unwrap());
535 }
536 for (i, c) in BytesToHexIter::new(bytes.iter(), Case::Upper).rev().enumerate() {
537 assert_eq!(c, upper_want.chars().nth(i).unwrap());
538 }
539 }
540
541 #[test]
542 fn roundtrip_forward() {
543 let lower_want = "deadbeefcafebabe";
544 let upper_want = "DEADBEEFCAFEBABE";
545 let lower_bytes_iter = HexToBytesIter::new(lower_want).unwrap().map(|res| res.unwrap());
546 let lower_got = BytesToHexIter::new(lower_bytes_iter, Case::Lower).collect::<String>();
547 assert_eq!(lower_got, lower_want);
548 let upper_bytes_iter = HexToBytesIter::new(upper_want).unwrap().map(|res| res.unwrap());
549 let upper_got = BytesToHexIter::new(upper_bytes_iter, Case::Upper).collect::<String>();
550 assert_eq!(upper_got, upper_want);
551 }
552
553 #[test]
554 fn roundtrip_backward() {
555 let lower_want = "deadbeefcafebabe";
556 let upper_want = "DEADBEEFCAFEBABE";
557 let lower_bytes_iter =
558 HexToBytesIter::new(lower_want).unwrap().rev().map(|res| res.unwrap());
559 let lower_got =
560 BytesToHexIter::new(lower_bytes_iter, Case::Lower).rev().collect::<String>();
561 assert_eq!(lower_got, lower_want);
562 let upper_bytes_iter =
563 HexToBytesIter::new(upper_want).unwrap().rev().map(|res| res.unwrap());
564 let upper_got =
565 BytesToHexIter::new(upper_bytes_iter, Case::Upper).rev().collect::<String>();
566 assert_eq!(upper_got, upper_want);
567 }
568}