1#[cfg(feature = "alloc")]
29use alloc::string::String;
30use core::borrow::Borrow;
31use core::fmt;
32
33use super::Case;
34#[cfg(feature = "std")]
35use super::Table;
36use crate::buf_encoder::BufEncoder;
37
38pub trait DisplayHex {
43 type Display<'a>: fmt::Display + fmt::Debug + fmt::LowerHex + fmt::UpperHex
47 where
48 Self: 'a;
49
50 fn as_hex<'a>(&'a self) -> Self::Display<'a>;
52
53 #[cfg(feature = "alloc")]
59 #[inline]
60 fn to_lower_hex_string(&self) -> String { self.to_hex_string(Case::Lower) }
61
62 #[cfg(feature = "alloc")]
68 #[inline]
69 fn to_upper_hex_string(&self) -> String { self.to_hex_string(Case::Upper) }
70
71 #[cfg(feature = "alloc")]
75 fn to_hex_string(&self, case: Case) -> String {
76 let mut string = String::new();
77 self.append_hex_to_string(case, &mut string);
78 string
79 }
80
81 #[cfg(feature = "alloc")]
86 fn append_hex_to_string<'a>(&'a self, case: Case, string: &mut String) {
87 use fmt::Write;
88
89 string.reserve(self.hex_reserve_suggestion());
90 match case {
91 Case::Lower => write!(string, "{:x}", self.as_hex()),
92 Case::Upper => write!(string, "{:X}", self.as_hex()),
93 }
94 .unwrap_or_else(|_| {
95 let name = core::any::type_name::<Self::Display<'a>>();
96 panic!("The implementation of Display for {} returned an error when it shouldn't", name)
99 });
100 }
101
102 fn hex_reserve_suggestion(&self) -> usize;
107}
108
109fn internal_display(bytes: &[u8], f: &mut fmt::Formatter, case: Case) -> fmt::Result {
110 use fmt::Write;
111 let mut encoder = BufEncoder::<1024>::new(case);
119 let pad_right = write_pad_left(f, bytes.len(), &mut encoder)?;
120
121 if f.alternate() {
122 f.write_str("0x")?;
123 }
124 match f.precision() {
125 Some(max) if bytes.len() > max / 2 => {
126 write!(f, "{}", bytes[..(max / 2)].as_hex())?;
127 if max % 2 == 1 {
128 f.write_char(case.table().byte_to_chars(bytes[max / 2])[0])?;
129 }
130 }
131 Some(_) | None => {
132 let mut chunks = bytes.chunks_exact(512);
133 for chunk in &mut chunks {
134 encoder.put_bytes(chunk);
135 f.write_str(encoder.as_str())?;
136 encoder.clear();
137 }
138 encoder.put_bytes(chunks.remainder());
139 f.write_str(encoder.as_str())?;
140 }
141 }
142
143 write_pad_right(f, pad_right, &mut encoder)
144}
145
146fn write_pad_left(
147 f: &mut fmt::Formatter,
148 bytes_len: usize,
149 encoder: &mut BufEncoder<1024>,
150) -> Result<usize, fmt::Error> {
151 let pad_right = if let Some(width) = f.width() {
152 let full_string_len = if f.alternate() { bytes_len * 2 + 2 } else { bytes_len * 2 };
154 let string_len = match f.precision() {
155 Some(max) => core::cmp::min(max, full_string_len),
156 None => full_string_len,
157 };
158
159 if string_len < width {
160 let (left, right) = match f.align().unwrap_or(fmt::Alignment::Left) {
161 fmt::Alignment::Left => (0, width - string_len),
162 fmt::Alignment::Right => (width - string_len, 0),
163 fmt::Alignment::Center =>
164 ((width - string_len) / 2, (width - string_len).div_ceil(2)),
165 };
166 if left > 0 {
168 let c = f.fill();
169 let chunk_len = encoder.put_filler(c, left);
170 let padding = encoder.as_str();
171 for _ in 0..(left / chunk_len) {
172 f.write_str(padding)?;
173 }
174 f.write_str(&padding[..((left % chunk_len) * c.len_utf8())])?;
175 encoder.clear();
176 }
177 right
178 } else {
179 0
180 }
181 } else {
182 0
183 };
184 Ok(pad_right)
185}
186
187fn write_pad_right(
188 f: &mut fmt::Formatter,
189 pad_right: usize,
190 encoder: &mut BufEncoder<1024>,
191) -> fmt::Result {
192 if pad_right > 0 {
194 encoder.clear();
195 let c = f.fill();
196 let chunk_len = encoder.put_filler(c, pad_right);
197 let padding = encoder.as_str();
198 for _ in 0..(pad_right / chunk_len) {
199 f.write_str(padding)?;
200 }
201 f.write_str(&padding[..((pad_right % chunk_len) * c.len_utf8())])?;
202 }
203 Ok(())
204}
205
206impl DisplayHex for [u8] {
207 type Display<'a> = DisplayByteSlice<'a>;
208
209 #[inline]
210 fn as_hex<'a>(&'a self) -> Self::Display<'a> { DisplayByteSlice { bytes: self } }
211
212 #[inline]
213 fn hex_reserve_suggestion(&self) -> usize {
214 self.len().checked_mul(2).expect("the string wouldn't fit into address space")
218 }
219}
220
221#[derive(Clone, PartialEq, Eq, Hash)]
225pub struct DisplayByteSlice<'a> {
226 pub(crate) bytes: &'a [u8],
228}
229
230impl DisplayByteSlice<'_> {
231 #[inline]
232 fn display(&self, f: &mut fmt::Formatter, case: Case) -> fmt::Result {
233 internal_display(self.bytes, f, case)
234 }
235}
236
237impl fmt::Display for DisplayByteSlice<'_> {
238 #[inline]
239 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
240}
241
242impl fmt::Debug for DisplayByteSlice<'_> {
243 #[inline]
244 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
245}
246
247impl fmt::LowerHex for DisplayByteSlice<'_> {
248 #[inline]
249 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Lower) }
250}
251
252impl fmt::UpperHex for DisplayByteSlice<'_> {
253 #[inline]
254 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Upper) }
255}
256
257#[macro_export]
280macro_rules! fmt_hex_exact {
281 ($formatter:expr, $len:expr, $bytes:expr, $case:expr) => {{
282 #[allow(deprecated)]
284 const _: () = [()][($len > usize::MAX / 2) as usize];
285 assert_eq!($bytes.len(), $len);
286 $crate::display::fmt_hex_exact_fn::<_, { $len * 2 }>($formatter, $bytes, $case)
287 }};
288}
289pub use fmt_hex_exact;
290
291#[macro_export]
376macro_rules! impl_fmt_traits {
377 (impl fmt_traits for $ty:ident { const LENGTH: usize = $len:expr; }) => {
379 $crate::impl_fmt_traits! {
380 #[display_backward(false)]
381 impl<> fmt_traits for $ty<> {
382 const LENGTH: usize = $len;
383 }
384 }
385 };
386 (#[display_backward($reverse:expr)] impl fmt_traits for $ty:ident { const LENGTH: usize = $len:expr; }) => {
388 $crate::impl_fmt_traits! {
389 #[display_backward($reverse)]
390 impl<> fmt_traits for $ty<> {
391 const LENGTH: usize = $len;
392 }
393 }
394 };
395 (impl<$($gen:ident: $gent:ident),*> fmt_traits for $ty:ident<$($unused:ident),*> { const LENGTH: usize = $len:expr; }) => {
397 $crate::impl_fmt_traits! {
398 #[display_backward(false)]
399 impl<$($gen: $gent),*> fmt_traits for $ty<$($unused),*> {
400 const LENGTH: usize = $len;
401 }
402 }
403 };
404 (#[display_backward($reverse:expr)] impl<$($gen:ident: $gent:ident),*> fmt_traits for $ty:ident<$($unused:ident),*> { const LENGTH: usize = $len:expr; }) => {
406 impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> {
407 #[inline]
408 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
409 let case = $crate::Case::Lower;
410
411 if $reverse {
412 let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter().rev();
413 $crate::fmt_hex_exact!(f, $len, bytes, case)
414 } else {
415 let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter();
416 $crate::fmt_hex_exact!(f, $len, bytes, case)
417 }
418 }
419 }
420
421 impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> {
422 #[inline]
423 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
424 let case = $crate::Case::Upper;
425
426 if $reverse {
427 let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter().rev();
428 $crate::fmt_hex_exact!(f, $len, bytes, case)
429 } else {
430 let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter();
431 $crate::fmt_hex_exact!(f, $len, bytes, case)
432 }
433 }
434 }
435
436 impl<$($gen: $gent),*> $crate::_export::_core::fmt::Display for $ty<$($gen),*> {
437 #[inline]
438 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
439 $crate::_export::_core::fmt::LowerHex::fmt(self, f)
440 }
441 }
442
443 impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> {
444 #[inline]
445 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
446 $crate::_export::_core::fmt::LowerHex::fmt(&self, f)
447 }
448 }
449 };
450}
451pub use impl_fmt_traits;
452
453#[doc(hidden)]
461#[inline]
462pub fn fmt_hex_exact_fn<I, const N: usize>(
463 f: &mut fmt::Formatter,
464 bytes: I,
465 case: Case,
466) -> fmt::Result
467where
468 I: IntoIterator,
469 I::Item: Borrow<u8>,
470{
471 let mut padding_encoder = BufEncoder::<1024>::new(case);
472 let pad_right = write_pad_left(f, N / 2, &mut padding_encoder)?;
473
474 if f.alternate() {
475 f.write_str("0x")?;
476 }
477 let mut encoder = BufEncoder::<N>::new(case);
478 let encoded = match f.precision() {
479 Some(p) if p < N => {
480 let n = p.div_ceil(2);
481 encoder.put_bytes(bytes.into_iter().take(n));
482 &encoder.as_str()[..p]
483 }
484 _ => {
485 encoder.put_bytes(bytes);
486 encoder.as_str()
487 }
488 };
489 f.write_str(encoded)?;
490
491 write_pad_right(f, pad_right, &mut padding_encoder)
492}
493
494#[cfg(feature = "std")]
497#[derive(Debug, Clone, PartialEq, Eq, Hash)]
498pub struct HexWriter<T> {
499 writer: T,
500 table: &'static Table,
501}
502
503#[cfg(feature = "std")]
504impl<T> HexWriter<T> {
505 pub fn new(dest: T, case: Case) -> Self { Self { writer: dest, table: case.table() } }
510 pub fn into_inner(self) -> T { self.writer }
512}
513
514#[cfg(feature = "std")]
515impl<T> std::io::Write for HexWriter<T>
516where
517 T: core::fmt::Write,
518{
519 fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
526 let mut n = 0;
527 for byte in buf {
528 let mut hex_chars = [0u8; 2];
529 let hex_str = self.table.byte_to_str(&mut hex_chars, *byte);
530 if self.writer.write_str(hex_str).is_err() {
531 break;
532 }
533 n += 1;
534 }
535 if n == 0 && !buf.is_empty() {
536 Err(std::io::ErrorKind::Other.into())
537 } else {
538 Ok(n)
539 }
540 }
541
542 fn flush(&mut self) -> Result<(), std::io::Error> { Ok(()) }
548}
549
550#[cfg(test)]
551mod tests {
552 #[cfg(feature = "alloc")]
553 use super::*;
554
555 #[cfg(feature = "alloc")]
556 mod alloc {
557 use core::marker::PhantomData;
558
559 use super::*;
560 use crate::alloc::vec::Vec;
561
562 fn check_encoding(bytes: &[u8]) {
563 use core::fmt::Write;
564
565 let s1 = bytes.to_lower_hex_string();
566 let mut s2 = String::with_capacity(bytes.len() * 2);
567 for b in bytes {
568 write!(s2, "{:02x}", b).unwrap();
569 }
570 assert_eq!(s1, s2);
571 }
572
573 #[test]
574 fn empty() { check_encoding(b""); }
575
576 #[test]
577 fn single() { check_encoding(b"*"); }
578
579 #[test]
580 fn two() { check_encoding(b"*x"); }
581
582 #[test]
583 fn just_below_boundary() { check_encoding(&[42; 512]); }
584
585 #[test]
586 fn just_above_boundary() { check_encoding(&[42; 513]); }
587
588 #[test]
589 fn just_above_double_boundary() { check_encoding(&[42; 1025]); }
590
591 #[test]
592 fn fmt_exact_macro() {
593 use crate::alloc::string::ToString;
594
595 struct Dummy([u8; 32]);
596
597 impl fmt::Display for Dummy {
598 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
599 fmt_hex_exact!(f, 32, &self.0, Case::Lower)
600 }
601 }
602 let dummy = Dummy([42; 32]);
603 assert_eq!(dummy.to_string(), "2a".repeat(32));
604 assert_eq!(format!("{:.10}", dummy), "2a".repeat(5));
605 assert_eq!(format!("{:.11}", dummy), "2a".repeat(5) + "2");
606 assert_eq!(format!("{:.65}", dummy), "2a".repeat(32));
607 }
608
609 macro_rules! define_dummy {
610 ($len:literal) => {
611 struct Dummy([u8; $len]);
612 impl fmt::Debug for Dummy {
613 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
614 fmt_hex_exact!(f, $len, &self.0, Case::Lower)
615 }
616 }
617 impl fmt::Display for Dummy {
618 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
619 fmt_hex_exact!(f, $len, &self.0, Case::Lower)
620 }
621 }
622 };
623 }
624
625 macro_rules! test_display_hex {
626 ($fs: expr, $a: expr, $check: expr) => {
627 let array = $a;
628 let slice = &$a;
629 let vec = Vec::from($a);
630 let dummy = Dummy($a);
631 assert_eq!(format!($fs, array.as_hex()), $check);
632 assert_eq!(format!($fs, slice.as_hex()), $check);
633 assert_eq!(format!($fs, vec.as_hex()), $check);
634 assert_eq!(format!($fs, dummy), $check);
635 };
636 }
637
638 #[test]
639 fn alternate_flag() {
640 define_dummy!(4);
641
642 test_display_hex!("{:#?}", [0xc0, 0xde, 0xca, 0xfe], "0xc0decafe");
643 test_display_hex!("{:#}", [0xc0, 0xde, 0xca, 0xfe], "0xc0decafe");
644 }
645
646 #[test]
647 fn display_short_with_padding() {
648 define_dummy!(2);
649
650 test_display_hex!("Hello {:<8}!", [0xbe, 0xef], "Hello beef !");
651 test_display_hex!("Hello {:-<8}!", [0xbe, 0xef], "Hello beef----!");
652 test_display_hex!("Hello {:^8}!", [0xbe, 0xef], "Hello beef !");
653 test_display_hex!("Hello {:>8}!", [0xbe, 0xef], "Hello beef!");
654
655 test_display_hex!("Hello {:<#8}!", [0xbe, 0xef], "Hello 0xbeef !");
656 test_display_hex!("Hello {:-<#8}!", [0xbe, 0xef], "Hello 0xbeef--!");
657 test_display_hex!("Hello {:^#8}!", [0xbe, 0xef], "Hello 0xbeef !");
658 test_display_hex!("Hello {:>#8}!", [0xbe, 0xef], "Hello 0xbeef!");
659 }
660
661 #[test]
662 fn display_long() {
663 define_dummy!(512);
664 let a = [0xab; 512];
666
667 let mut want = "0".repeat(2000 - 1024);
668 want.extend(core::iter::repeat("ab").take(512));
669 test_display_hex!("{:0>2000}", a, want);
670
671 let mut want = "0".repeat(2000 - 1026);
672 want.push_str("0x");
673 want.extend(core::iter::repeat("ab").take(512));
674 test_display_hex!("{:0>#2000}", a, want);
675 }
676
677 #[test]
680 fn precision_truncates() {
681 define_dummy!(4);
684
685 test_display_hex!("{0:.4}", [0x12, 0x34, 0x56, 0x78], "1234");
686 test_display_hex!("{0:.5}", [0x12, 0x34, 0x56, 0x78], "12345");
687
688 test_display_hex!("{0:#.4}", [0x12, 0x34, 0x56, 0x78], "0x1234");
689 test_display_hex!("{0:#.5}", [0x12, 0x34, 0x56, 0x78], "0x12345");
690 }
691
692 #[test]
693 fn precision_with_padding_truncates() {
694 define_dummy!(4);
696
697 test_display_hex!("{0:10.4}", [0x12, 0x34, 0x56, 0x78], "1234 ");
698 test_display_hex!("{0:10.5}", [0x12, 0x34, 0x56, 0x78], "12345 ");
699
700 test_display_hex!("{0:#10.4}", [0x12, 0x34, 0x56, 0x78], "0x1234 ");
701 test_display_hex!("{0:#10.5}", [0x12, 0x34, 0x56, 0x78], "0x12345 ");
702 }
703
704 #[test]
705 fn precision_with_padding_pads_right() {
706 define_dummy!(4);
707
708 test_display_hex!("{0:10.20}", [0x12, 0x34, 0x56, 0x78], "12345678 ");
709 test_display_hex!("{0:10.14}", [0x12, 0x34, 0x56, 0x78], "12345678 ");
710
711 test_display_hex!("{0:#12.20}", [0x12, 0x34, 0x56, 0x78], "0x12345678 ");
712 test_display_hex!("{0:#12.14}", [0x12, 0x34, 0x56, 0x78], "0x12345678 ");
713 }
714
715 #[test]
716 fn precision_with_padding_pads_left() {
717 define_dummy!(4);
718
719 test_display_hex!("{0:>10.20}", [0x12, 0x34, 0x56, 0x78], " 12345678");
720
721 test_display_hex!("{0:>#12.20}", [0x12, 0x34, 0x56, 0x78], " 0x12345678");
722 }
723
724 #[test]
725 fn precision_with_padding_pads_center() {
726 define_dummy!(4);
727
728 test_display_hex!("{0:^10.20}", [0x12, 0x34, 0x56, 0x78], " 12345678 ");
729
730 test_display_hex!("{0:^#12.20}", [0x12, 0x34, 0x56, 0x78], " 0x12345678 ");
731 }
732
733 #[test]
734 fn precision_with_padding_pads_center_odd() {
735 define_dummy!(4);
736
737 test_display_hex!("{0:^11.20}", [0x12, 0x34, 0x56, 0x78], " 12345678 ");
738
739 test_display_hex!("{0:^#13.20}", [0x12, 0x34, 0x56, 0x78], " 0x12345678 ");
740 }
741
742 #[test]
743 fn precision_does_not_extend() {
744 define_dummy!(4);
745
746 test_display_hex!("{0:.16}", [0x12, 0x34, 0x56, 0x78], "12345678");
747
748 test_display_hex!("{0:#.16}", [0x12, 0x34, 0x56, 0x78], "0x12345678");
749 }
750
751 #[test]
752 fn padding_extends() {
753 define_dummy!(2);
754
755 test_display_hex!("{:0>8}", [0xab; 2], "0000abab");
756
757 test_display_hex!("{:0>#8}", [0xab; 2], "000xabab");
758 }
759
760 #[test]
761 fn padding_does_not_truncate() {
762 define_dummy!(4);
763
764 test_display_hex!("{:0>4}", [0x12, 0x34, 0x56, 0x78], "12345678");
765 test_display_hex!("{:0>4}", [0x12, 0x34, 0x56, 0x78], "12345678");
766
767 test_display_hex!("{:0>#4}", [0x12, 0x34, 0x56, 0x78], "0x12345678");
768 test_display_hex!("{:0>#4}", [0x12, 0x34, 0x56, 0x78], "0x12345678");
769 }
770
771 #[allow(dead_code)]
774 struct Wrapper([u8; 4]);
775
776 impl Borrow<[u8]> for Wrapper {
777 fn borrow(&self) -> &[u8] { &self.0[..] }
778 }
779
780 impl_fmt_traits! {
781 #[display_backward(false)]
782 impl fmt_traits for Wrapper {
783 const LENGTH: usize = 4;
784 }
785 }
786
787 #[test]
788 fn hex_fmt_impl_macro_forward() {
789 struct Wrapper([u8; 4]);
790
791 impl Borrow<[u8]> for Wrapper {
792 fn borrow(&self) -> &[u8] { &self.0[..] }
793 }
794
795 impl_fmt_traits! {
796 #[display_backward(false)]
797 impl fmt_traits for Wrapper {
798 const LENGTH: usize = 4;
799 }
800 }
801
802 let tc = Wrapper([0x12, 0x34, 0x56, 0x78]);
803
804 let want = "12345678";
805 let got = format!("{}", tc);
806 assert_eq!(got, want);
807 }
808
809 #[test]
810 fn hex_fmt_impl_macro_backwards() {
811 struct Wrapper([u8; 4]);
812
813 impl Borrow<[u8]> for Wrapper {
814 fn borrow(&self) -> &[u8] { &self.0[..] }
815 }
816
817 impl_fmt_traits! {
818 #[display_backward(true)]
819 impl fmt_traits for Wrapper {
820 const LENGTH: usize = 4;
821 }
822 }
823
824 let tc = Wrapper([0x12, 0x34, 0x56, 0x78]);
825
826 let want = "78563412";
827 let got = format!("{}", tc);
828 assert_eq!(got, want);
829 }
830
831 #[test]
832 fn hex_fmt_impl_macro_gen_forward() {
833 struct Wrapper<T>([u8; 4], PhantomData<T>);
834
835 impl<T: Clone> Borrow<[u8]> for Wrapper<T> {
836 fn borrow(&self) -> &[u8] { &self.0[..] }
837 }
838
839 impl_fmt_traits! {
840 #[display_backward(false)]
841 impl<T: Clone> fmt_traits for Wrapper<T> {
842 const LENGTH: usize = 4;
843 }
844 }
845
846 let tc = Wrapper([0x12, 0x34, 0x56, 0x78], PhantomData::<u32>);
848
849 let want = "12345678";
850 let got = format!("{}", tc);
851 assert_eq!(got, want);
852 }
853
854 #[test]
855 fn hex_fmt_impl_macro_gen_backwards() {
856 struct Wrapper<T>([u8; 4], PhantomData<T>);
857
858 impl<T: Clone> Borrow<[u8]> for Wrapper<T> {
859 fn borrow(&self) -> &[u8] { &self.0[..] }
860 }
861
862 impl_fmt_traits! {
863 #[display_backward(true)]
864 impl<T: Clone> fmt_traits for Wrapper<T> {
865 const LENGTH: usize = 4;
866 }
867 }
868
869 let tc = Wrapper([0x12, 0x34, 0x56, 0x78], PhantomData::<u32>);
871
872 let want = "78563412";
873 let got = format!("{}", tc);
874 assert_eq!(got, want);
875 }
876
877 #[test]
878 fn hex_display_case() {
879 let bytes = [0xaa, 0xbb, 0xcc, 0xdd];
880 let upper = "AABBCCDD";
881 let lower = "aabbccdd";
882 assert_eq!(bytes.to_upper_hex_string(), upper);
883 assert_eq!(bytes.to_lower_hex_string(), lower);
884 }
885 }
886
887 #[cfg(feature = "std")]
888 mod std {
889 use alloc::string::String;
890 use alloc::vec::Vec;
891 use std::io::Write as _;
892
893 use arrayvec::ArrayString;
894
895 use super::{Case, DisplayHex, HexWriter};
896
897 #[test]
898 fn hex_writer() {
899 use std::io::{ErrorKind, Result, Write};
900
901 use super::Case::{Lower, Upper};
902
903 macro_rules! test_hex_writer {
904 ($cap:expr, $case: expr, $src: expr, $want: expr, $hex_result: expr) => {
905 let dest_buf = ArrayString::<$cap>::new();
906 let mut dest = HexWriter::new(dest_buf, $case);
907 let got = dest.write($src);
908 match $want {
909 Ok(n) => assert_eq!(got.unwrap(), n),
910 Err(e) => assert_eq!(got.unwrap_err().kind(), e.kind()),
911 }
912 assert_eq!(dest.into_inner().as_str(), $hex_result);
913 };
914 }
915
916 test_hex_writer!(0, Lower, &[], Result::Ok(0), "");
917 test_hex_writer!(
918 0,
919 Lower,
920 &[0xab, 0xcd],
921 Result::<usize>::Err(ErrorKind::Other.into()),
922 ""
923 );
924 test_hex_writer!(
925 1,
926 Lower,
927 &[0xab, 0xcd],
928 Result::<usize>::Err(ErrorKind::Other.into()),
929 ""
930 );
931 test_hex_writer!(2, Lower, &[0xab, 0xcd], Result::Ok(1), "ab");
932 test_hex_writer!(3, Lower, &[0xab, 0xcd], Result::Ok(1), "ab");
933 test_hex_writer!(4, Lower, &[0xab, 0xcd], Result::Ok(2), "abcd");
934 test_hex_writer!(8, Lower, &[0xab, 0xcd], Result::Ok(2), "abcd");
935 test_hex_writer!(8, Upper, &[0xab, 0xcd], Result::Ok(2), "ABCD");
936
937 let vec: Vec<_> = (0u8..32).collect();
938 let mut writer = HexWriter::new(String::new(), Lower);
939 writer.write_all(&vec[..]).unwrap();
940 assert_eq!(writer.into_inner(), vec.to_lower_hex_string());
941 }
942
943 #[test]
944 fn hex_writer_accepts_and_mut() {
945 let mut dest_buf = ArrayString::<64>::new();
946 let mut dest = HexWriter::new(&mut dest_buf, Case::Lower);
947 let _got = dest.write(b"some data").unwrap();
948 }
949 }
950}