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(feature = "alloc")]
13use crate::alloc::vec::Vec;
14use crate::error::{InvalidCharError, OddLengthStringError};
15use crate::{Case, Char, Table};
16
17#[derive(Debug, Clone)]
25pub struct HexSliceToBytesIter<'a>(HexToBytesIter<HexDigitsIter<'a>>);
26
27impl<'a> HexSliceToBytesIter<'a> {
28 #[inline]
48 pub fn new(s: &'a str) -> Result<Self, OddLengthStringError> {
49 HexToBytesIter::new(s).map(Self)
50 }
51}
52
53impl Iterator for HexSliceToBytesIter<'_> {
54 type Item = Result<u8, InvalidCharError>;
55
56 #[inline]
57 fn next(&mut self) -> Option<Self::Item> { self.0.next() }
58
59 #[inline]
60 fn size_hint(&self) -> (usize, Option<usize>) { self.0.size_hint() }
61
62 #[inline]
63 fn nth(&mut self, n: usize) -> Option<Self::Item> { self.0.nth(n) }
64}
65
66impl DoubleEndedIterator for HexSliceToBytesIter<'_> {
67 #[inline]
68 fn next_back(&mut self) -> Option<Self::Item> { self.0.next_back() }
69
70 #[inline]
71 fn nth_back(&mut self, n: usize) -> Option<Self::Item> { self.0.nth_back(n) }
72}
73
74impl ExactSizeIterator for HexSliceToBytesIter<'_> {}
75
76impl FusedIterator for HexSliceToBytesIter<'_> {}
77
78#[cfg(feature = "std")]
79impl io::Read for HexSliceToBytesIter<'_> {
80 #[inline]
81 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> { self.0.read(buf) }
82}
83
84#[derive(Debug, Clone, PartialEq, Eq, Hash)]
86pub struct HexToBytesIter<I>
87where
88 I: Iterator<Item = [u8; 2]>,
89{
90 iter: I,
91 front_pos: usize,
93}
94
95impl<'a> HexToBytesIter<HexDigitsIter<'a>> {
96 #[inline]
102 pub(crate) fn new(s: &'a str) -> Result<Self, OddLengthStringError> {
103 if s.len() % 2 != 0 {
104 Err(OddLengthStringError { len: s.len() })
105 } else {
106 Ok(Self::new_unchecked(s))
107 }
108 }
109
110 #[inline]
111 pub(crate) fn new_unchecked(s: &'a str) -> Self {
112 Self::from_pairs(HexDigitsIter::new_unchecked(s.as_bytes()))
113 }
114
115 pub(crate) fn drain_to_slice(self, buf: &mut [u8]) -> Result<(), InvalidCharError> {
124 assert_eq!(self.len(), buf.len());
125 let mut ptr = buf.as_mut_ptr();
126 for byte in self {
127 unsafe {
129 core::ptr::write(ptr, byte?);
130 ptr = ptr.add(1);
131 }
132 }
133 Ok(())
134 }
135
136 #[cfg(feature = "alloc")]
141 pub(crate) fn drain_to_vec(self) -> Result<Vec<u8>, InvalidCharError> {
142 let len = self.len();
143 let mut ret = Vec::with_capacity(len);
144 let mut ptr = ret.as_mut_ptr();
145 for byte in self {
146 unsafe {
148 core::ptr::write(ptr, byte?);
150 ptr = ptr.add(1);
151 }
152 }
153 unsafe {
155 ret.set_len(len);
156 }
157 Ok(ret)
158 }
159}
160
161impl<I> HexToBytesIter<I>
162where
163 I: Iterator<Item = [u8; 2]> + ExactSizeIterator,
164{
165 #[inline]
183 pub fn from_pairs(iter: I) -> Self { Self { front_pos: 0, iter } }
184}
185
186impl<I> Iterator for HexToBytesIter<I>
187where
188 I: Iterator<Item = [u8; 2]> + ExactSizeIterator,
189{
190 type Item = Result<u8, InvalidCharError>;
191
192 #[inline]
193 fn next(&mut self) -> Option<Self::Item> { self.nth(0) }
194
195 #[inline]
196 fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
197
198 #[inline]
199 fn nth(&mut self, n: usize) -> Option<Self::Item> {
200 let [hi, lo] = self.iter.nth(n)?;
201 let pos = self.front_pos.saturating_add(n).saturating_mul(2);
202 self.front_pos = self.front_pos.saturating_add(n).saturating_add(1);
203 Some(hex_chars_to_byte(hi, lo).map_err(|(c, is_high)| InvalidCharError {
204 invalid: c,
205 pos: if is_high { pos } else { pos.saturating_add(1) },
206 }))
207 }
208}
209
210impl<I> DoubleEndedIterator for HexToBytesIter<I>
211where
212 I: Iterator<Item = [u8; 2]> + DoubleEndedIterator + ExactSizeIterator,
213{
214 #[inline]
215 fn next_back(&mut self) -> Option<Self::Item> { self.nth_back(0) }
216
217 #[inline]
218 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
219 let [hi, lo] = self.iter.nth_back(n)?;
220 let pos = (self.front_pos + self.iter.len()).saturating_mul(2);
221 Some(hex_chars_to_byte(hi, lo).map_err(|(c, is_high)| InvalidCharError {
222 invalid: c,
223 pos: if is_high { pos } else { pos.saturating_add(1) },
224 }))
225 }
226}
227
228impl<I> ExactSizeIterator for HexToBytesIter<I> where I: Iterator<Item = [u8; 2]> + ExactSizeIterator
229{}
230
231impl<I> FusedIterator for HexToBytesIter<I> where
232 I: Iterator<Item = [u8; 2]> + ExactSizeIterator + FusedIterator
233{
234}
235
236#[cfg(feature = "std")]
237impl<I> io::Read for HexToBytesIter<I>
238where
239 I: Iterator<Item = [u8; 2]> + ExactSizeIterator + FusedIterator,
240{
241 #[inline]
242 fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
243 let mut bytes_read = 0usize;
244 for dst in buf {
245 match self.next() {
246 Some(Ok(src)) => {
247 *dst = src;
248 bytes_read += 1;
249 }
250 Some(Err(e)) => return Err(io::Error::new(io::ErrorKind::InvalidData, e)),
251 None => break,
252 }
253 }
254 Ok(bytes_read)
255 }
256}
257
258#[derive(Debug, Clone)]
264pub struct HexDigitsIter<'a> {
265 iter: core::slice::ChunksExact<'a, u8>,
269}
270
271impl<'a> HexDigitsIter<'a> {
272 #[inline]
273 fn new_unchecked(digits: &'a [u8]) -> Self { Self { iter: digits.chunks_exact(2) } }
274}
275
276impl Iterator for HexDigitsIter<'_> {
277 type Item = [u8; 2];
278
279 #[inline]
280 fn next(&mut self) -> Option<Self::Item> {
281 self.iter.next().map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
282 }
283
284 #[inline]
285 fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
286
287 #[inline]
288 fn nth(&mut self, n: usize) -> Option<Self::Item> {
289 self.iter.nth(n).map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
290 }
291}
292
293impl DoubleEndedIterator for HexDigitsIter<'_> {
294 #[inline]
295 fn next_back(&mut self) -> Option<Self::Item> {
296 self.iter.next_back().map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
297 }
298
299 #[inline]
300 fn nth_back(&mut self, n: usize) -> Option<Self::Item> {
301 self.iter.nth_back(n).map(|digits| digits.try_into().expect("HexDigitsIter invariant"))
302 }
303}
304
305impl ExactSizeIterator for HexDigitsIter<'_> {}
306
307impl core::iter::FusedIterator for HexDigitsIter<'_> {}
308
309fn hex_chars_to_byte(hi: u8, lo: u8) -> Result<u8, (u8, bool)> {
313 let hih = Char::decode_nibble(hi).ok_or((hi, true))?;
314 let loh = Char::decode_nibble(lo).ok_or((lo, false))?;
315 Ok((hih << 4) | loh)
316}
317
318#[derive(Debug, Clone, PartialEq, Eq, Hash)]
341pub struct BytesToHexIter<I>
342where
343 I: Iterator,
344 I::Item: Borrow<u8>,
345{
346 iter: I,
348 table: &'static Table,
350}
351
352impl<I> BytesToHexIter<I>
353where
354 I: Iterator,
355 I::Item: Borrow<u8>,
356{
357 pub fn new(iter: I, case: Case) -> BytesToHexIter<I> { Self { iter, table: case.table() } }
360}
361
362impl<I> Iterator for BytesToHexIter<I>
363where
364 I: Iterator,
365 I::Item: Borrow<u8>,
366{
367 type Item = [Char; 2];
368
369 #[inline]
370 fn next(&mut self) -> Option<[Char; 2]> {
371 self.iter.next().map(|b| self.table.byte_to_hex_chars(*b.borrow()))
372 }
373
374 #[inline]
375 fn size_hint(&self) -> (usize, Option<usize>) { self.iter.size_hint() }
376
377 #[inline]
378 fn nth(&mut self, n: usize) -> Option<[Char; 2]> {
379 self.iter.nth(n).map(|b| self.table.byte_to_hex_chars(*b.borrow()))
380 }
381}
382
383impl<I> DoubleEndedIterator for BytesToHexIter<I>
384where
385 I: DoubleEndedIterator,
386 I::Item: Borrow<u8>,
387{
388 #[inline]
389 fn next_back(&mut self) -> Option<[Char; 2]> {
390 self.iter.next_back().map(|b| self.table.byte_to_hex_chars(*b.borrow()))
391 }
392
393 #[inline]
394 fn nth_back(&mut self, n: usize) -> Option<[Char; 2]> {
395 self.iter.nth_back(n).map(|b| self.table.byte_to_hex_chars(*b.borrow()))
396 }
397}
398
399impl<I> ExactSizeIterator for BytesToHexIter<I>
400where
401 I: ExactSizeIterator,
402 I::Item: Borrow<u8>,
403{
404 #[inline]
405 fn len(&self) -> usize { self.iter.len() }
406}
407
408impl<I> FusedIterator for BytesToHexIter<I>
409where
410 I: FusedIterator,
411 I::Item: Borrow<u8>,
412{
413}
414
415#[cfg(test)]
416mod tests {
417 #[cfg(feature = "alloc")]
418 use alloc::string::String;
419
420 use super::*;
421
422 fn nth_slow<I: Iterator>(iter: &mut I, n: usize) -> Option<I::Item> {
423 for _ in 0..n {
424 iter.next()?;
425 }
426 iter.next()
427 }
428
429 fn nth_back_slow<I: DoubleEndedIterator>(iter: &mut I, n: usize) -> Option<I::Item> {
430 for _ in 0..n {
431 iter.next_back()?;
432 }
433 iter.next_back()
434 }
435
436 #[test]
437 fn encode_byte() {
438 assert_eq!(Table::LOWER.byte_to_chars(0x00), ['0', '0']);
439 assert_eq!(Table::LOWER.byte_to_chars(0x0a), ['0', 'a']);
440 assert_eq!(Table::LOWER.byte_to_chars(0xad), ['a', 'd']);
441 assert_eq!(Table::LOWER.byte_to_chars(0xff), ['f', 'f']);
442
443 assert_eq!(Table::UPPER.byte_to_chars(0x00), ['0', '0']);
444 assert_eq!(Table::UPPER.byte_to_chars(0x0a), ['0', 'A']);
445 assert_eq!(Table::UPPER.byte_to_chars(0xad), ['A', 'D']);
446 assert_eq!(Table::UPPER.byte_to_chars(0xff), ['F', 'F']);
447
448 let mut buf = [0u8; 2];
449 assert_eq!(Table::LOWER.byte_to_str(&mut buf, 0x00), "00");
450 assert_eq!(Table::LOWER.byte_to_str(&mut buf, 0x0a), "0a");
451 assert_eq!(Table::LOWER.byte_to_str(&mut buf, 0xad), "ad");
452 assert_eq!(Table::LOWER.byte_to_str(&mut buf, 0xff), "ff");
453
454 assert_eq!(Table::UPPER.byte_to_str(&mut buf, 0x00), "00");
455 assert_eq!(Table::UPPER.byte_to_str(&mut buf, 0x0a), "0A");
456 assert_eq!(Table::UPPER.byte_to_str(&mut buf, 0xad), "AD");
457 assert_eq!(Table::UPPER.byte_to_str(&mut buf, 0xff), "FF");
458 }
459
460 #[test]
461 fn decode_iter_forward() {
462 let hex = "deadbeef";
463 let bytes = [0xde, 0xad, 0xbe, 0xef];
464
465 for (i, b) in HexToBytesIter::new(hex).unwrap().enumerate() {
466 assert_eq!(b.unwrap(), bytes[i]);
467 }
468
469 let mut iter = HexToBytesIter::new(hex).unwrap();
470 for i in (0..=bytes.len()).rev() {
471 assert_eq!(iter.len(), i);
472 let _ = iter.next();
473 }
474 }
475
476 #[test]
477 fn decode_iter_backward() {
478 let hex = "deadbeef";
479 let bytes = [0xef, 0xbe, 0xad, 0xde];
480
481 for (i, b) in HexToBytesIter::new(hex).unwrap().rev().enumerate() {
482 assert_eq!(b.unwrap(), bytes[i]);
483 }
484
485 let mut iter = HexToBytesIter::new(hex).unwrap().rev();
486 for i in (0..=bytes.len()).rev() {
487 assert_eq!(iter.len(), i);
488 let _ = iter.next();
489 }
490 }
491
492 #[test]
493 fn hex_to_digits_size_hint() {
494 let hex = "deadbeef";
495 let iter = HexDigitsIter::new_unchecked(hex.as_bytes());
496 assert_eq!(iter.size_hint(), (4, Some(4)));
498 }
499
500 #[test]
501 fn hex_to_bytes_size_hint() {
502 let hex = "deadbeef";
503 let iter = HexToBytesIter::new_unchecked(hex);
504 assert_eq!(iter.size_hint(), (4, Some(4)));
505 }
506
507 #[test]
508 fn hex_to_bytes_slice_drain() {
509 let hex = "deadbeef";
510 let want = [0xde, 0xad, 0xbe, 0xef];
511 let iter = HexToBytesIter::new_unchecked(hex);
512 let mut got = [0u8; 4];
513 iter.drain_to_slice(&mut got).unwrap();
514 assert_eq!(got, want);
515
516 let hex = "";
517 let want: [u8; 0] = [];
518 let iter = HexToBytesIter::new_unchecked(hex);
519 let mut got = [];
520 iter.drain_to_slice(&mut got).unwrap();
521 assert_eq!(got, want);
522 }
523
524 #[test]
525 #[should_panic]
526 #[allow(clippy::should_panic_without_expect)]
528 fn hex_to_bytes_slice_drain_panic_empty() {
529 let hex = "deadbeef";
530 let iter = HexToBytesIter::new_unchecked(hex);
531 let mut got = [];
532 iter.drain_to_slice(&mut got).unwrap();
533 }
534
535 #[test]
536 #[should_panic]
537 #[allow(clippy::should_panic_without_expect)]
539 fn hex_to_bytes_slice_drain_panic_too_small() {
540 let hex = "deadbeef";
541 let iter = HexToBytesIter::new_unchecked(hex);
542 let mut got = [0u8; 3];
543 iter.drain_to_slice(&mut got).unwrap();
544 }
545
546 #[test]
547 #[should_panic]
548 #[allow(clippy::should_panic_without_expect)]
550 fn hex_to_bytes_slice_drain_panic_too_big() {
551 let hex = "deadbeef";
552 let iter = HexToBytesIter::new_unchecked(hex);
553 let mut got = [0u8; 5];
554 iter.drain_to_slice(&mut got).unwrap();
555 }
556
557 #[test]
558 fn hex_to_bytes_slice_drain_first_char_error() {
559 let hex = "geadbeef";
560 let iter = HexToBytesIter::new_unchecked(hex);
561 let mut got = [0u8; 4];
562 assert_eq!(
563 iter.drain_to_slice(&mut got).unwrap_err(),
564 InvalidCharError { invalid: b'g', pos: 0 }
565 );
566 }
567
568 #[test]
569 fn hex_to_bytes_slice_drain_middle_char_error() {
570 let hex = "deadgeef";
571 let iter = HexToBytesIter::new_unchecked(hex);
572 let mut got = [0u8; 4];
573 assert_eq!(
574 iter.drain_to_slice(&mut got).unwrap_err(),
575 InvalidCharError { invalid: b'g', pos: 4 }
576 );
577 }
578
579 #[test]
580 fn hex_to_bytes_slice_drain_end_char_error() {
581 let hex = "deadbeeg";
582 let iter = HexToBytesIter::new_unchecked(hex);
583 let mut got = [0u8; 4];
584 assert_eq!(
585 iter.drain_to_slice(&mut got).unwrap_err(),
586 InvalidCharError { invalid: b'g', pos: 7 }
587 );
588 }
589
590 #[cfg(feature = "alloc")]
591 #[test]
592 fn hex_to_bytes_vec_drain() {
593 let hex = "deadbeef";
594 let want = [0xde, 0xad, 0xbe, 0xef];
595 let iter = HexToBytesIter::new_unchecked(hex);
596 let got = iter.drain_to_vec().unwrap();
597 assert_eq!(got, want);
598
599 let hex = "";
600 let iter = HexToBytesIter::new_unchecked(hex);
601 let got = iter.drain_to_vec().unwrap();
602 assert!(got.is_empty());
603 }
604
605 #[cfg(feature = "alloc")]
606 #[test]
607 fn hex_to_bytes_vec_drain_first_char_error() {
608 let hex = "geadbeef";
609 let iter = HexToBytesIter::new_unchecked(hex);
610 assert_eq!(iter.drain_to_vec().unwrap_err(), InvalidCharError { invalid: b'g', pos: 0 });
611 }
612
613 #[cfg(feature = "alloc")]
614 #[test]
615 fn hex_to_bytes_vec_drain_middle_char_error() {
616 let hex = "deadgeef";
617 let iter = HexToBytesIter::new_unchecked(hex);
618 assert_eq!(iter.drain_to_vec().unwrap_err(), InvalidCharError { invalid: b'g', pos: 4 });
619 }
620
621 #[cfg(feature = "alloc")]
622 #[test]
623 fn hex_to_bytes_vec_drain_end_char_error() {
624 let hex = "deadbeeg";
625 let iter = HexToBytesIter::new_unchecked(hex);
626 assert_eq!(iter.drain_to_vec().unwrap_err(), InvalidCharError { invalid: b'g', pos: 7 });
627 }
628
629 #[test]
630 fn decode_error_pos_after_next_back() {
631 let mut iter = HexToBytesIter::new("geadbeef").unwrap();
632 iter.next_back().unwrap().unwrap();
633 assert_eq!(iter.next().unwrap().unwrap_err(), InvalidCharError { invalid: b'g', pos: 0 },);
634 }
635
636 #[test]
637 fn decode_error_pos_after_next() {
638 let mut iter = HexToBytesIter::new("deadbeGf").unwrap();
639 iter.next().unwrap().unwrap();
640 assert_eq!(
641 iter.next_back().unwrap().unwrap_err(),
642 InvalidCharError { invalid: b'G', pos: 6 },
643 );
644 }
645
646 #[cfg(feature = "alloc")]
647 #[test]
648 fn encode_iter() {
649 let bytes = [0xde, 0xad, 0xbe, 0xef];
650 let lower_want = "deadbeef";
651 let upper_want = "DEADBEEF";
652
653 let lower_got: String =
654 BytesToHexIter::new(bytes.iter(), Case::Lower).flatten().map(char::from).collect();
655 assert_eq!(lower_got, lower_want);
656 let upper_got: String =
657 BytesToHexIter::new(bytes.iter(), Case::Upper).flatten().map(char::from).collect();
658 assert_eq!(upper_got, upper_want);
659 }
660
661 #[cfg(feature = "alloc")]
662 #[test]
663 fn encode_iter_backwards() {
664 let bytes = [0xde, 0xad, 0xbe, 0xef];
665 let lower_want = "efbeadde";
667 let upper_want = "EFBEADDE";
668
669 let lower_got: String = BytesToHexIter::new(bytes.iter(), Case::Lower)
670 .rev()
671 .flatten()
672 .map(char::from)
673 .collect();
674 assert_eq!(lower_got, lower_want);
675 let upper_got: String = BytesToHexIter::new(bytes.iter(), Case::Upper)
676 .rev()
677 .flatten()
678 .map(char::from)
679 .collect();
680 assert_eq!(upper_got, upper_want);
681
682 let lower_want = "feebdaed";
684 let upper_want = "FEEBDAED";
685
686 let lower_got: String = BytesToHexIter::new(bytes.iter(), Case::Lower)
687 .flatten()
688 .rev()
689 .map(char::from)
690 .collect();
691 assert_eq!(lower_got, lower_want);
692 let upper_got: String = BytesToHexIter::new(bytes.iter(), Case::Upper)
693 .flatten()
694 .rev()
695 .map(char::from)
696 .collect();
697 assert_eq!(upper_got, upper_want);
698 }
699
700 #[test]
701 fn encode_iter_nth() {
702 let bytes = [0xde, 0xad, 0xbe, 0xef];
703
704 for n in 0..=bytes.len() + 1 {
705 let mut got = BytesToHexIter::new(bytes.iter(), Case::Lower);
706 let mut want = BytesToHexIter::new(bytes.iter(), Case::Lower);
707
708 assert_eq!(got.nth(n), nth_slow(&mut want, n));
709 assert_eq!(got.len(), want.len());
710 assert!(got.eq(want));
711 }
712 }
713
714 #[test]
715 fn encode_iter_nth_after_next_back() {
716 let bytes = [0xde, 0xad, 0xbe, 0xef];
717
718 for n in 0..=bytes.len() {
719 let mut got = BytesToHexIter::new(bytes.iter(), Case::Lower);
720 let mut want = BytesToHexIter::new(bytes.iter(), Case::Lower);
721
722 assert_eq!(got.next_back(), want.next_back());
723 assert_eq!(got.nth(n), nth_slow(&mut want, n));
724 assert_eq!(got.len(), want.len());
725 assert!(got.eq(want));
726 }
727 }
728
729 #[test]
730 fn encode_iter_nth_after_next() {
731 let bytes = [0xde, 0xad, 0xbe, 0xef];
732
733 for n in 0..=bytes.len() {
734 let mut got = BytesToHexIter::new(bytes.iter(), Case::Lower);
735 let mut want = BytesToHexIter::new(bytes.iter(), Case::Lower);
736
737 assert_eq!(got.next(), want.next());
738 assert_eq!(got.nth(n), nth_slow(&mut want, n));
739 assert_eq!(got.len(), want.len());
740 assert!(got.eq(want));
741 }
742 }
743
744 #[test]
745 fn encode_iter_nth_back() {
746 let bytes = [0xde, 0xad, 0xbe, 0xef];
747
748 for n in 0..=bytes.len() + 1 {
749 let mut got = BytesToHexIter::new(bytes.iter(), Case::Lower);
750 let mut want = BytesToHexIter::new(bytes.iter(), Case::Lower);
751
752 assert_eq!(got.nth_back(n), nth_back_slow(&mut want, n));
753 assert_eq!(got.len(), want.len());
754 assert!(got.eq(want));
755 }
756 }
757
758 #[test]
759 fn encode_iter_nth_back_after_next() {
760 let bytes = [0xde, 0xad, 0xbe, 0xef];
761
762 for n in 0..=bytes.len() {
763 let mut got = BytesToHexIter::new(bytes.iter(), Case::Lower);
764 let mut want = BytesToHexIter::new(bytes.iter(), Case::Lower);
765
766 assert_eq!(got.next(), want.next());
767 assert_eq!(got.nth_back(n), nth_back_slow(&mut want, n));
768 assert_eq!(got.len(), want.len());
769 assert!(got.eq(want));
770 }
771 }
772
773 #[test]
774 fn encode_iter_nth_back_after_next_back() {
775 let bytes = [0xde, 0xad, 0xbe, 0xef];
776
777 for n in 0..=bytes.len() {
778 let mut got = BytesToHexIter::new(bytes.iter(), Case::Lower);
779 let mut want = BytesToHexIter::new(bytes.iter(), Case::Lower);
780
781 assert_eq!(got.next_back(), want.next_back());
782 assert_eq!(got.nth_back(n), nth_back_slow(&mut want, n));
783 assert_eq!(got.len(), want.len());
784 assert!(got.eq(want));
785 }
786 }
787
788 #[cfg(feature = "alloc")]
789 #[test]
790 fn roundtrip_forward() {
791 let lower_want = "deadbeefcafebabe";
792 let upper_want = "DEADBEEFCAFEBABE";
793 let lower_bytes_iter = HexToBytesIter::new(lower_want).unwrap().map(|res| res.unwrap());
794 let lower_got: String =
795 BytesToHexIter::new(lower_bytes_iter, Case::Lower).flatten().map(char::from).collect();
796 assert_eq!(lower_got, lower_want);
797 let upper_bytes_iter = HexToBytesIter::new(upper_want).unwrap().map(|res| res.unwrap());
798 let upper_got: String =
799 BytesToHexIter::new(upper_bytes_iter, Case::Upper).flatten().map(char::from).collect();
800 assert_eq!(upper_got, upper_want);
801 }
802
803 #[cfg(feature = "alloc")]
804 #[test]
805 fn roundtrip_backward() {
806 let lower_want = "deadbeefcafebabe";
807 let upper_want = "DEADBEEFCAFEBABE";
808 let lower_bytes_iter =
809 HexToBytesIter::new(lower_want).unwrap().rev().map(|res| res.unwrap());
810 let lower_got: String = BytesToHexIter::new(lower_bytes_iter, Case::Lower)
811 .rev()
812 .flatten()
813 .map(char::from)
814 .collect();
815 assert_eq!(lower_got, lower_want);
816 let upper_bytes_iter =
817 HexToBytesIter::new(upper_want).unwrap().rev().map(|res| res.unwrap());
818 let upper_got: String = BytesToHexIter::new(upper_bytes_iter, Case::Upper)
819 .rev()
820 .flatten()
821 .map(char::from)
822 .collect();
823 assert_eq!(upper_got, upper_want);
824 }
825
826 #[test]
827 #[cfg(feature = "std")]
828 fn hex_to_bytes_iter_read() {
829 use std::io::Read;
830
831 let hex = "deadbeef";
832 let mut iter = HexToBytesIter::new(hex).unwrap();
833 let mut buf = [0u8; 4];
834 let bytes_read = iter.read(&mut buf).unwrap();
835 assert_eq!(bytes_read, 4);
836 assert_eq!(buf, [0xde, 0xad, 0xbe, 0xef]);
837
838 let hex = "deadbeef";
839 let mut iter = HexToBytesIter::new(hex).unwrap();
840 let mut buf = [0u8; 2];
841 let bytes_read = iter.read(&mut buf).unwrap();
842 assert_eq!(bytes_read, 2);
843 assert_eq!(buf, [0xde, 0xad]);
844
845 let hex = "deadbeef";
846 let mut iter = HexToBytesIter::new(hex).unwrap();
847 let mut buf = [0u8; 6];
848 let bytes_read = iter.read(&mut buf).unwrap();
849 assert_eq!(bytes_read, 4);
850 assert_eq!(buf[..4], [0xde, 0xad, 0xbe, 0xef]);
851
852 let hex = "deadbeefXX";
853 let mut iter = HexToBytesIter::new(hex).unwrap();
854 let mut buf = [0u8; 6];
855 let err = iter.read(&mut buf).unwrap_err();
856 assert_eq!(err.kind(), io::ErrorKind::InvalidData);
857 }
858}