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