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]
316macro_rules! fmt_hex_max {
317 ($formatter:expr, $len:expr, $bytes:expr, $case:expr) => {{
318 #[allow(deprecated)]
320 const _: () = [()][($len > usize::MAX / 2) as usize];
321 assert!(
322 $bytes.len() <= $len,
323 "length of the encoded item ({}) is larger than {}",
324 $bytes.len(),
325 $len
326 );
327 $crate::display::fmt_hex_max_fn::<_, { $len * 2 }>($formatter, $bytes, $case)
328 }};
329}
330pub use fmt_hex_max;
331
332#[macro_export]
340macro_rules! fmt_hex_exact {
341 ($formatter:expr, $len:expr, $bytes:expr, $case:expr) => {{
342 assert_eq!($bytes.len(), $len);
343 $crate::fmt_hex_max!($formatter, $len, $bytes, $case)
344 }};
345}
346pub use fmt_hex_exact;
347
348#[macro_export]
352macro_rules! fmt_hex_lower {
353 ($formatter:expr, $len:expr, $bytes:expr) => {
354 $crate::fmt_hex_max!($formatter, $len, $bytes, $crate::Case::Lower)
355 };
356}
357pub use fmt_hex_lower;
358
359#[macro_export]
363macro_rules! fmt_hex_upper {
364 ($formatter:expr, $len:expr, $bytes:expr) => {
365 $crate::fmt_hex_max!($formatter, $len, $bytes, $crate::Case::Upper)
366 };
367}
368pub use fmt_hex_upper;
369
370#[macro_export]
455macro_rules! impl_fmt_traits {
456 (impl fmt_traits for $ty:ident { const LENGTH: usize = $len:expr; }) => {
458 $crate::impl_fmt_traits! {
459 #[display_backward(false)]
460 impl<> fmt_traits for $ty<> {
461 const LENGTH: usize = $len;
462 }
463 }
464 };
465 (#[display_backward($reverse:expr)] impl fmt_traits for $ty:ident { const LENGTH: usize = $len:expr; }) => {
467 $crate::impl_fmt_traits! {
468 #[display_backward($reverse)]
469 impl<> fmt_traits for $ty<> {
470 const LENGTH: usize = $len;
471 }
472 }
473 };
474 (impl<$($gen:ident: $gent:ident),*> fmt_traits for $ty:ident<$($unused:ident),*> { const LENGTH: usize = $len:expr; }) => {
476 $crate::impl_fmt_traits! {
477 #[display_backward(false)]
478 impl<$($gen: $gent),*> fmt_traits for $ty<$($unused),*> {
479 const LENGTH: usize = $len;
480 }
481 }
482 };
483 (#[display_backward($reverse:expr)] impl<$($gen:ident: $gent:ident),*> fmt_traits for $ty:ident<$($unused:ident),*> { const LENGTH: usize = $len:expr; }) => {
485 impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> {
486 #[inline]
487 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
488 let case = $crate::Case::Lower;
489
490 if $reverse {
491 let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter().rev();
492 $crate::fmt_hex_exact!(f, $len, bytes, case)
493 } else {
494 let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter();
495 $crate::fmt_hex_exact!(f, $len, bytes, case)
496 }
497 }
498 }
499
500 impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> {
501 #[inline]
502 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
503 let case = $crate::Case::Upper;
504
505 if $reverse {
506 let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter().rev();
507 $crate::fmt_hex_exact!(f, $len, bytes, case)
508 } else {
509 let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter();
510 $crate::fmt_hex_exact!(f, $len, bytes, case)
511 }
512 }
513 }
514
515 impl<$($gen: $gent),*> $crate::_export::_core::fmt::Display for $ty<$($gen),*> {
516 #[inline]
517 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
518 $crate::_export::_core::fmt::LowerHex::fmt(self, f)
519 }
520 }
521
522 impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> {
523 #[inline]
524 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
525 $crate::_export::_core::fmt::LowerHex::fmt(&self, f)
526 }
527 }
528 };
529}
530pub use impl_fmt_traits;
531
532#[doc(hidden)]
540#[inline]
541pub fn fmt_hex_max_fn<I, const N: usize>(
542 f: &mut fmt::Formatter,
543 bytes: I,
544 case: Case,
545) -> fmt::Result
546where
547 I: IntoIterator,
548 I::Item: Borrow<u8>,
549{
550 let mut padding_encoder = BufEncoder::<1024>::new(case);
551 let pad_right = write_pad_left(f, N / 2, &mut padding_encoder)?;
552
553 if f.alternate() {
554 f.write_str("0x")?;
555 }
556 let mut encoder = BufEncoder::<N>::new(case);
557 let encoded = match f.precision() {
558 Some(p) if p < N => {
559 let n = p.div_ceil(2);
560 encoder.put_bytes(bytes.into_iter().take(n));
561 &encoder.as_str()[..p]
562 }
563 _ => {
564 encoder.put_bytes(bytes);
565 encoder.as_str()
566 }
567 };
568 f.write_str(encoded)?;
569
570 write_pad_right(f, pad_right, &mut padding_encoder)
571}
572
573#[cfg(feature = "std")]
576#[derive(Debug, Clone, PartialEq, Eq, Hash)]
577pub struct HexWriter<T> {
578 writer: T,
579 table: &'static Table,
580}
581
582#[cfg(feature = "std")]
583impl<T> HexWriter<T> {
584 pub fn new(dest: T, case: Case) -> Self { Self { writer: dest, table: case.table() } }
589 pub fn into_inner(self) -> T { self.writer }
591}
592
593#[cfg(feature = "std")]
594impl<T> std::io::Write for HexWriter<T>
595where
596 T: core::fmt::Write,
597{
598 fn write(&mut self, buf: &[u8]) -> Result<usize, std::io::Error> {
605 let mut n = 0;
606 for byte in buf {
607 let mut hex_chars = [0u8; 2];
608 let hex_str = self.table.byte_to_str(&mut hex_chars, *byte);
609 if self.writer.write_str(hex_str).is_err() {
610 break;
611 }
612 n += 1;
613 }
614 if n == 0 && !buf.is_empty() {
615 Err(std::io::ErrorKind::Other.into())
616 } else {
617 Ok(n)
618 }
619 }
620
621 fn flush(&mut self) -> Result<(), std::io::Error> { Ok(()) }
627}
628
629#[cfg(test)]
630mod tests {
631 #[cfg(feature = "alloc")]
632 use super::*;
633
634 #[cfg(feature = "alloc")]
635 mod alloc {
636 use core::marker::PhantomData;
637
638 use super::*;
639 use crate::alloc::vec::Vec;
640
641 fn check_encoding(bytes: &[u8]) {
642 use core::fmt::Write;
643
644 let s1 = bytes.to_lower_hex_string();
645 let mut s2 = String::with_capacity(bytes.len() * 2);
646 for b in bytes {
647 write!(s2, "{:02x}", b).unwrap();
648 }
649 assert_eq!(s1, s2);
650 }
651
652 #[test]
653 fn empty() { check_encoding(b""); }
654
655 #[test]
656 fn single() { check_encoding(b"*"); }
657
658 #[test]
659 fn two() { check_encoding(b"*x"); }
660
661 #[test]
662 fn just_below_boundary() { check_encoding(&[42; 512]); }
663
664 #[test]
665 fn just_above_boundary() { check_encoding(&[42; 513]); }
666
667 #[test]
668 fn just_above_double_boundary() { check_encoding(&[42; 1025]); }
669
670 #[test]
671 fn fmt_exact_macro() {
672 use crate::alloc::string::ToString;
673
674 struct Dummy([u8; 32]);
675
676 impl fmt::Display for Dummy {
677 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
678 fmt_hex_exact!(f, 32, &self.0, Case::Lower)
679 }
680 }
681 let dummy = Dummy([42; 32]);
682 assert_eq!(dummy.to_string(), "2a".repeat(32));
683 assert_eq!(format!("{:.10}", dummy), "2a".repeat(5));
684 assert_eq!(format!("{:.11}", dummy), "2a".repeat(5) + "2");
685 assert_eq!(format!("{:.65}", dummy), "2a".repeat(32));
686 }
687
688 struct TestHexUpperLower<'a>(&'a [u8], bool);
689
690 impl fmt::Display for TestHexUpperLower<'_> {
691 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
692 if self.1 {
693 fmt_hex_upper!(f, 3, self.0)
694 } else {
695 fmt_hex_lower!(f, 3, self.0)
696 }
697 }
698 }
699
700 #[test]
701 fn fmt_hex_lower_macro() {
702 let bytes = [0x1a, 0x2b, 0x3c];
703 assert_eq!(format!("{}", TestHexUpperLower(&bytes, false)), "1a2b3c");
704 }
705
706 #[test]
707 fn fmt_hex_upper_macro() {
708 let bytes = [0x1a, 0x2b, 0x3c];
709 assert_eq!(format!("{}", TestHexUpperLower(&bytes, true)), "1A2B3C");
710 }
711
712 macro_rules! define_dummy {
713 ($len:literal) => {
714 struct Dummy([u8; $len]);
715 impl fmt::Debug for Dummy {
716 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
717 fmt_hex_exact!(f, $len, &self.0, Case::Lower)
718 }
719 }
720 impl fmt::Display for Dummy {
721 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
722 fmt_hex_exact!(f, $len, &self.0, Case::Lower)
723 }
724 }
725 };
726 }
727
728 macro_rules! test_display_hex {
729 ($fs: expr, $a: expr, $check: expr) => {
730 let array = $a;
731 let slice = &$a;
732 let vec = Vec::from($a);
733 let dummy = Dummy($a);
734 assert_eq!(format!($fs, array.as_hex()), $check);
735 assert_eq!(format!($fs, slice.as_hex()), $check);
736 assert_eq!(format!($fs, vec.as_hex()), $check);
737 assert_eq!(format!($fs, dummy), $check);
738 };
739 }
740
741 #[test]
742 fn alternate_flag() {
743 define_dummy!(4);
744
745 test_display_hex!("{:#?}", [0xc0, 0xde, 0xca, 0xfe], "0xc0decafe");
746 test_display_hex!("{:#}", [0xc0, 0xde, 0xca, 0xfe], "0xc0decafe");
747 }
748
749 #[test]
750 fn display_short_with_padding() {
751 define_dummy!(2);
752
753 test_display_hex!("Hello {:<8}!", [0xbe, 0xef], "Hello beef !");
754 test_display_hex!("Hello {:-<8}!", [0xbe, 0xef], "Hello beef----!");
755 test_display_hex!("Hello {:^8}!", [0xbe, 0xef], "Hello beef !");
756 test_display_hex!("Hello {:>8}!", [0xbe, 0xef], "Hello beef!");
757
758 test_display_hex!("Hello {:<#8}!", [0xbe, 0xef], "Hello 0xbeef !");
759 test_display_hex!("Hello {:-<#8}!", [0xbe, 0xef], "Hello 0xbeef--!");
760 test_display_hex!("Hello {:^#8}!", [0xbe, 0xef], "Hello 0xbeef !");
761 test_display_hex!("Hello {:>#8}!", [0xbe, 0xef], "Hello 0xbeef!");
762 }
763
764 #[test]
765 fn display_long() {
766 define_dummy!(512);
767 let a = [0xab; 512];
769
770 let mut want = "0".repeat(2000 - 1024);
771 want.extend(core::iter::repeat("ab").take(512));
772 test_display_hex!("{:0>2000}", a, want);
773
774 let mut want = "0".repeat(2000 - 1026);
775 want.push_str("0x");
776 want.extend(core::iter::repeat("ab").take(512));
777 test_display_hex!("{:0>#2000}", a, want);
778 }
779
780 #[test]
783 fn precision_truncates() {
784 define_dummy!(4);
787
788 test_display_hex!("{0:.4}", [0x12, 0x34, 0x56, 0x78], "1234");
789 test_display_hex!("{0:.5}", [0x12, 0x34, 0x56, 0x78], "12345");
790
791 test_display_hex!("{0:#.4}", [0x12, 0x34, 0x56, 0x78], "0x1234");
792 test_display_hex!("{0:#.5}", [0x12, 0x34, 0x56, 0x78], "0x12345");
793 }
794
795 #[test]
796 fn precision_with_padding_truncates() {
797 define_dummy!(4);
799
800 test_display_hex!("{0:10.4}", [0x12, 0x34, 0x56, 0x78], "1234 ");
801 test_display_hex!("{0:10.5}", [0x12, 0x34, 0x56, 0x78], "12345 ");
802
803 test_display_hex!("{0:#10.4}", [0x12, 0x34, 0x56, 0x78], "0x1234 ");
804 test_display_hex!("{0:#10.5}", [0x12, 0x34, 0x56, 0x78], "0x12345 ");
805 }
806
807 #[test]
808 fn precision_with_padding_pads_right() {
809 define_dummy!(4);
810
811 test_display_hex!("{0:10.20}", [0x12, 0x34, 0x56, 0x78], "12345678 ");
812 test_display_hex!("{0:10.14}", [0x12, 0x34, 0x56, 0x78], "12345678 ");
813
814 test_display_hex!("{0:#12.20}", [0x12, 0x34, 0x56, 0x78], "0x12345678 ");
815 test_display_hex!("{0:#12.14}", [0x12, 0x34, 0x56, 0x78], "0x12345678 ");
816 }
817
818 #[test]
819 fn precision_with_padding_pads_left() {
820 define_dummy!(4);
821
822 test_display_hex!("{0:>10.20}", [0x12, 0x34, 0x56, 0x78], " 12345678");
823
824 test_display_hex!("{0:>#12.20}", [0x12, 0x34, 0x56, 0x78], " 0x12345678");
825 }
826
827 #[test]
828 fn precision_with_padding_pads_center() {
829 define_dummy!(4);
830
831 test_display_hex!("{0:^10.20}", [0x12, 0x34, 0x56, 0x78], " 12345678 ");
832
833 test_display_hex!("{0:^#12.20}", [0x12, 0x34, 0x56, 0x78], " 0x12345678 ");
834 }
835
836 #[test]
837 fn precision_with_padding_pads_center_odd() {
838 define_dummy!(4);
839
840 test_display_hex!("{0:^11.20}", [0x12, 0x34, 0x56, 0x78], " 12345678 ");
841
842 test_display_hex!("{0:^#13.20}", [0x12, 0x34, 0x56, 0x78], " 0x12345678 ");
843 }
844
845 #[test]
846 fn precision_does_not_extend() {
847 define_dummy!(4);
848
849 test_display_hex!("{0:.16}", [0x12, 0x34, 0x56, 0x78], "12345678");
850
851 test_display_hex!("{0:#.16}", [0x12, 0x34, 0x56, 0x78], "0x12345678");
852 }
853
854 #[test]
855 fn padding_extends() {
856 define_dummy!(2);
857
858 test_display_hex!("{:0>8}", [0xab; 2], "0000abab");
859
860 test_display_hex!("{:0>#8}", [0xab; 2], "000xabab");
861 }
862
863 #[test]
864 fn padding_does_not_truncate() {
865 define_dummy!(4);
866
867 test_display_hex!("{:0>4}", [0x12, 0x34, 0x56, 0x78], "12345678");
868 test_display_hex!("{:0>4}", [0x12, 0x34, 0x56, 0x78], "12345678");
869
870 test_display_hex!("{:0>#4}", [0x12, 0x34, 0x56, 0x78], "0x12345678");
871 test_display_hex!("{:0>#4}", [0x12, 0x34, 0x56, 0x78], "0x12345678");
872 }
873
874 #[allow(dead_code)]
877 struct Wrapper([u8; 4]);
878
879 impl Borrow<[u8]> for Wrapper {
880 fn borrow(&self) -> &[u8] { &self.0[..] }
881 }
882
883 impl_fmt_traits! {
884 #[display_backward(false)]
885 impl fmt_traits for Wrapper {
886 const LENGTH: usize = 4;
887 }
888 }
889
890 #[test]
891 fn hex_fmt_impl_macro_forward() {
892 struct Wrapper([u8; 4]);
893
894 impl Borrow<[u8]> for Wrapper {
895 fn borrow(&self) -> &[u8] { &self.0[..] }
896 }
897
898 impl_fmt_traits! {
899 #[display_backward(false)]
900 impl fmt_traits for Wrapper {
901 const LENGTH: usize = 4;
902 }
903 }
904
905 let tc = Wrapper([0x12, 0x34, 0x56, 0x78]);
906
907 let want = "12345678";
908 let got = format!("{}", tc);
909 assert_eq!(got, want);
910 }
911
912 #[test]
913 fn hex_fmt_impl_macro_backwards() {
914 struct Wrapper([u8; 4]);
915
916 impl Borrow<[u8]> for Wrapper {
917 fn borrow(&self) -> &[u8] { &self.0[..] }
918 }
919
920 impl_fmt_traits! {
921 #[display_backward(true)]
922 impl fmt_traits for Wrapper {
923 const LENGTH: usize = 4;
924 }
925 }
926
927 let tc = Wrapper([0x12, 0x34, 0x56, 0x78]);
928
929 let want = "78563412";
930 let got = format!("{}", tc);
931 assert_eq!(got, want);
932 }
933
934 #[test]
935 fn hex_fmt_impl_macro_gen_forward() {
936 struct Wrapper<T>([u8; 4], PhantomData<T>);
937
938 impl<T: Clone> Borrow<[u8]> for Wrapper<T> {
939 fn borrow(&self) -> &[u8] { &self.0[..] }
940 }
941
942 impl_fmt_traits! {
943 #[display_backward(false)]
944 impl<T: Clone> fmt_traits for Wrapper<T> {
945 const LENGTH: usize = 4;
946 }
947 }
948
949 let tc = Wrapper([0x12, 0x34, 0x56, 0x78], PhantomData::<u32>);
951
952 let want = "12345678";
953 let got = format!("{}", tc);
954 assert_eq!(got, want);
955 }
956
957 #[test]
958 fn hex_fmt_impl_macro_gen_backwards() {
959 struct Wrapper<T>([u8; 4], PhantomData<T>);
960
961 impl<T: Clone> Borrow<[u8]> for Wrapper<T> {
962 fn borrow(&self) -> &[u8] { &self.0[..] }
963 }
964
965 impl_fmt_traits! {
966 #[display_backward(true)]
967 impl<T: Clone> fmt_traits for Wrapper<T> {
968 const LENGTH: usize = 4;
969 }
970 }
971
972 let tc = Wrapper([0x12, 0x34, 0x56, 0x78], PhantomData::<u32>);
974
975 let want = "78563412";
976 let got = format!("{}", tc);
977 assert_eq!(got, want);
978 }
979
980 #[test]
981 fn hex_display_case() {
982 let bytes = [0xaa, 0xbb, 0xcc, 0xdd];
983 let upper = "AABBCCDD";
984 let lower = "aabbccdd";
985 assert_eq!(bytes.to_upper_hex_string(), upper);
986 assert_eq!(bytes.to_lower_hex_string(), lower);
987 }
988 }
989
990 #[cfg(feature = "std")]
991 mod std {
992 use alloc::string::String;
993 use alloc::vec::Vec;
994 use std::io::Write as _;
995
996 use arrayvec::ArrayString;
997
998 use super::{Case, DisplayHex, HexWriter};
999
1000 #[test]
1001 fn hex_writer() {
1002 use std::io::{ErrorKind, Result, Write};
1003
1004 use super::Case::{Lower, Upper};
1005
1006 macro_rules! test_hex_writer {
1007 ($cap:expr, $case: expr, $src: expr, $want: expr, $hex_result: expr) => {
1008 let dest_buf = ArrayString::<$cap>::new();
1009 let mut dest = HexWriter::new(dest_buf, $case);
1010 let got = dest.write($src);
1011 match $want {
1012 Ok(n) => assert_eq!(got.unwrap(), n),
1013 Err(e) => assert_eq!(got.unwrap_err().kind(), e.kind()),
1014 }
1015 assert_eq!(dest.into_inner().as_str(), $hex_result);
1016 };
1017 }
1018
1019 test_hex_writer!(0, Lower, &[], Result::Ok(0), "");
1020 test_hex_writer!(
1021 0,
1022 Lower,
1023 &[0xab, 0xcd],
1024 Result::<usize>::Err(ErrorKind::Other.into()),
1025 ""
1026 );
1027 test_hex_writer!(
1028 1,
1029 Lower,
1030 &[0xab, 0xcd],
1031 Result::<usize>::Err(ErrorKind::Other.into()),
1032 ""
1033 );
1034 test_hex_writer!(2, Lower, &[0xab, 0xcd], Result::Ok(1), "ab");
1035 test_hex_writer!(3, Lower, &[0xab, 0xcd], Result::Ok(1), "ab");
1036 test_hex_writer!(4, Lower, &[0xab, 0xcd], Result::Ok(2), "abcd");
1037 test_hex_writer!(8, Lower, &[0xab, 0xcd], Result::Ok(2), "abcd");
1038 test_hex_writer!(8, Upper, &[0xab, 0xcd], Result::Ok(2), "ABCD");
1039
1040 let vec: Vec<_> = (0u8..32).collect();
1041 let mut writer = HexWriter::new(String::new(), Lower);
1042 writer.write_all(&vec[..]).unwrap();
1043 assert_eq!(writer.into_inner(), vec.to_lower_hex_string());
1044 }
1045
1046 #[test]
1047 fn hex_writer_accepts_and_mut() {
1048 let mut dest_buf = ArrayString::<64>::new();
1049 let mut dest = HexWriter::new(&mut dest_buf, Case::Lower);
1050 let _got = dest.write(b"some data").unwrap();
1051 }
1052 }
1053}