1#[cfg(all(feature = "alloc", not(feature = "std")))]
29use alloc::string::String;
30use core::borrow::Borrow;
31use core::fmt;
32
33use super::Case;
34use crate::buf_encoder::BufEncoder;
35
36pub trait DisplayHex: Copy + sealed::IsRef {
45 type Display: fmt::Display + fmt::Debug + fmt::LowerHex + fmt::UpperHex;
49
50 fn as_hex(self) -> Self::Display;
52
53 #[cfg(feature = "alloc")]
59 fn to_lower_hex_string(self) -> String { self.to_hex_string(Case::Lower) }
60
61 #[cfg(feature = "alloc")]
67 fn to_upper_hex_string(self) -> String { self.to_hex_string(Case::Upper) }
68
69 #[cfg(feature = "alloc")]
73 fn to_hex_string(self, case: Case) -> String {
74 let mut string = String::new();
75 self.append_hex_to_string(case, &mut string);
76 string
77 }
78
79 #[cfg(feature = "alloc")]
84 fn append_hex_to_string(self, case: Case, string: &mut String) {
85 use fmt::Write;
86
87 string.reserve(self.hex_reserve_suggestion());
88 match case {
89 Case::Lower => write!(string, "{:x}", self.as_hex()),
90 Case::Upper => write!(string, "{:X}", self.as_hex()),
91 }
92 .unwrap_or_else(|_| {
93 let name = core::any::type_name::<Self::Display>();
94 panic!("The implementation of Display for {} returned an error when it shouldn't", name)
97 })
98 }
99
100 fn hex_reserve_suggestion(self) -> usize { 0 }
107}
108
109mod sealed {
110 pub trait IsRef: Copy {}
112
113 impl<T: ?Sized> IsRef for &'_ T {}
114}
115
116impl<'a> DisplayHex for &'a [u8] {
117 type Display = DisplayByteSlice<'a>;
118
119 #[inline]
120 fn as_hex(self) -> Self::Display { DisplayByteSlice { bytes: self } }
121
122 #[inline]
123 fn hex_reserve_suggestion(self) -> usize {
124 self.len().checked_mul(2).expect("the string wouldn't fit into address space")
128 }
129}
130
131#[cfg(feature = "alloc")]
132impl<'a> DisplayHex for &'a alloc::vec::Vec<u8> {
133 type Display = DisplayByteSlice<'a>;
134
135 #[inline]
136 fn as_hex(self) -> Self::Display { DisplayByteSlice { bytes: self } }
137
138 #[inline]
139 fn hex_reserve_suggestion(self) -> usize {
140 self.len().checked_mul(2).expect("the string wouldn't fit into address space")
144 }
145}
146
147pub struct DisplayByteSlice<'a> {
151 pub(crate) bytes: &'a [u8],
153}
154
155impl<'a> DisplayByteSlice<'a> {
156 fn display(&self, f: &mut fmt::Formatter, case: Case) -> fmt::Result {
157 use fmt::Write;
158 let mut encoder = BufEncoder::<1024>::new();
166
167 let pad_right = if let Some(width) = f.width() {
168 let string_len = match f.precision() {
169 Some(max) if self.bytes.len() * 2 > (max + 1) / 2 => max,
170 Some(_) | None => self.bytes.len() * 2,
171 };
172
173 if string_len < width {
174 let (left, right) = match f.align().unwrap_or(fmt::Alignment::Left) {
175 fmt::Alignment::Left => (0, width - string_len),
176 fmt::Alignment::Right => (width - string_len, 0),
177 fmt::Alignment::Center =>
178 ((width - string_len) / 2, (width - string_len + 1) / 2),
179 };
180 if left > 0 {
182 let c = f.fill();
183 let chunk_len = encoder.put_filler(c, left);
184 let padding = encoder.as_str();
185 for _ in 0..(left / chunk_len) {
186 f.write_str(padding)?;
187 }
188 f.write_str(&padding[..((left % chunk_len) * c.len_utf8())])?;
189 encoder.clear();
190 }
191 right
192 } else {
193 0
194 }
195 } else {
196 0
197 };
198
199 match f.precision() {
200 Some(max) if self.bytes.len() > (max + 1) / 2 => {
201 write!(f, "{}", self.bytes[..(max / 2)].as_hex())?;
202 if max % 2 == 1 && self.bytes.len() > max / 2 + 1 {
203 f.write_char(
204 case.table().byte_to_hex(self.bytes[max / 2 + 1]).as_bytes()[1].into(),
205 )?;
206 }
207 }
208 Some(_) | None => {
209 let mut chunks = self.bytes.chunks_exact(512);
210 for chunk in &mut chunks {
211 encoder.put_bytes(chunk, case);
212 f.write_str(encoder.as_str())?;
213 encoder.clear();
214 }
215 encoder.put_bytes(chunks.remainder(), case);
216 f.write_str(encoder.as_str())?;
217 }
218 }
219
220 if pad_right > 0 {
222 encoder.clear();
223 let c = f.fill();
224 let chunk_len = encoder.put_filler(c, pad_right);
225 let padding = encoder.as_str();
226 for _ in 0..(pad_right / chunk_len) {
227 f.write_str(padding)?;
228 }
229 f.write_str(&padding[..((pad_right % chunk_len) * c.len_utf8())])?;
230 }
231 Ok(())
232 }
233}
234
235impl<'a> fmt::Display for DisplayByteSlice<'a> {
236 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
237}
238
239impl<'a> fmt::Debug for DisplayByteSlice<'a> {
240 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
241}
242
243impl<'a> fmt::LowerHex for DisplayByteSlice<'a> {
244 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Lower) }
245}
246
247impl<'a> fmt::UpperHex for DisplayByteSlice<'a> {
248 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Upper) }
249}
250
251pub struct DisplayArray<'a, const CAP: usize> {
255 array: &'a [u8],
256}
257
258impl<'a, const CAP: usize> DisplayArray<'a, CAP> {
259 #[inline]
265 fn new(array: &'a [u8]) -> Self {
266 assert!(array.len() <= CAP / 2);
267 DisplayArray { array }
268 }
269
270 fn display(&self, f: &mut fmt::Formatter, case: Case) -> fmt::Result {
271 let mut encoder = BufEncoder::<CAP>::new();
272 encoder.put_bytes(self.array, case);
273 f.pad_integral(true, "0x", encoder.as_str())
274 }
275}
276
277impl<'a, const LEN: usize> fmt::Display for DisplayArray<'a, LEN> {
278 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
279}
280
281impl<'a, const LEN: usize> fmt::Debug for DisplayArray<'a, LEN> {
282 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { fmt::LowerHex::fmt(self, f) }
283}
284
285impl<'a, const LEN: usize> fmt::LowerHex for DisplayArray<'a, LEN> {
286 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Lower) }
287}
288
289impl<'a, const LEN: usize> fmt::UpperHex for DisplayArray<'a, LEN> {
290 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(f, Case::Upper) }
291}
292
293macro_rules! impl_array_as_hex {
294 ($($len:expr),*) => {
295 $(
296 impl<'a> DisplayHex for &'a [u8; $len] {
297 type Display = DisplayArray<'a, {$len * 2}>;
298
299 fn as_hex(self) -> Self::Display {
300 DisplayArray::new(self)
301 }
302 }
303 )*
304 }
305}
306
307impl_array_as_hex!(
308 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 20, 32, 33, 64, 65, 128, 256, 512, 1024,
309 2048, 4096
310);
311
312#[macro_export]
335macro_rules! fmt_hex_exact {
336 ($formatter:expr, $len:expr, $bytes:expr, $case:expr) => {{
337 #[allow(deprecated)]
339 const _: () = [()][($len > usize::MAX / 2) as usize];
340 assert_eq!($bytes.len(), $len);
341 $crate::display::fmt_hex_exact_fn::<_, { $len * 2 }>($formatter, $bytes, $case)
342 }};
343}
344pub use fmt_hex_exact;
345
346#[macro_export]
431macro_rules! impl_fmt_traits {
432 (impl fmt_traits for $ty:ident { const LENGTH: usize = $len:expr; }) => {
434 $crate::impl_fmt_traits! {
435 #[display_backward(false)]
436 impl<> fmt_traits for $ty<> {
437 const LENGTH: usize = $len;
438 }
439 }
440 };
441 (#[display_backward($reverse:expr)] impl fmt_traits for $ty:ident { const LENGTH: usize = $len:expr; }) => {
443 $crate::impl_fmt_traits! {
444 #[display_backward($reverse)]
445 impl<> fmt_traits for $ty<> {
446 const LENGTH: usize = $len;
447 }
448 }
449 };
450 (impl<$($gen:ident: $gent:ident),*> fmt_traits for $ty:ident<$($unused:ident),*> { const LENGTH: usize = $len:expr; }) => {
452 $crate::impl_fmt_traits! {
453 #[display_backward(false)]
454 impl<$($gen: $gent),*> fmt_traits for $ty<$($unused),*> {
455 const LENGTH: usize = $len;
456 }
457 }
458 };
459 (#[display_backward($reverse:expr)] impl<$($gen:ident: $gent:ident),*> fmt_traits for $ty:ident<$($unused:ident),*> { const LENGTH: usize = $len:expr; }) => {
461 impl<$($gen: $gent),*> $crate::_export::_core::fmt::LowerHex for $ty<$($gen),*> {
462 #[inline]
463 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
464 let case = $crate::Case::Lower;
465
466 if $reverse {
467 let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter().rev();
468 $crate::fmt_hex_exact!(f, $len, bytes, case)
469 } else {
470 let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter();
471 $crate::fmt_hex_exact!(f, $len, bytes, case)
472 }
473 }
474 }
475
476 impl<$($gen: $gent),*> $crate::_export::_core::fmt::UpperHex for $ty<$($gen),*> {
477 #[inline]
478 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
479 let case = $crate::Case::Upper;
480
481 if $reverse {
482 let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter().rev();
483 $crate::fmt_hex_exact!(f, $len, bytes, case)
484 } else {
485 let bytes = $crate::_export::_core::borrow::Borrow::<[u8]>::borrow(self).iter();
486 $crate::fmt_hex_exact!(f, $len, bytes, case)
487 }
488 }
489 }
490
491 impl<$($gen: $gent),*> $crate::_export::_core::fmt::Display for $ty<$($gen),*> {
492 #[inline]
493 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
494 $crate::_export::_core::fmt::LowerHex::fmt(self, f)
495 }
496 }
497
498 impl<$($gen: $gent),*> $crate::_export::_core::fmt::Debug for $ty<$($gen),*> {
499 #[inline]
500 fn fmt(&self, f: &mut $crate::_export::_core::fmt::Formatter) -> $crate::_export::_core::fmt::Result {
501 $crate::_export::_core::fmt::LowerHex::fmt(&self, f)
502 }
503 }
504 };
505}
506pub use impl_fmt_traits;
507
508#[doc(hidden)]
514#[inline]
515pub fn fmt_hex_exact_fn<I, const N: usize>(
516 f: &mut fmt::Formatter,
517 bytes: I,
518 case: Case,
519) -> fmt::Result
520where
521 I: IntoIterator,
522 I::Item: Borrow<u8>,
523{
524 let mut encoder = BufEncoder::<N>::new();
525 encoder.put_bytes(bytes, case);
526 let encoded = encoder.as_str();
527
528 if let Some(precision) = f.precision() {
529 if encoded.len() > precision {
530 return f.pad_integral(true, "0x", &encoded[..precision]);
531 }
532 }
533 f.pad_integral(true, "0x", encoded)
534}
535
536#[cfg(test)]
537mod tests {
538 #[cfg(feature = "alloc")]
539 use super::*;
540
541 #[cfg(feature = "alloc")]
542 mod alloc {
543 use core::marker::PhantomData;
544
545 use super::*;
546
547 fn check_encoding(bytes: &[u8]) {
548 use core::fmt::Write;
549
550 let s1 = bytes.to_lower_hex_string();
551 let mut s2 = String::with_capacity(bytes.len() * 2);
552 for b in bytes {
553 write!(s2, "{:02x}", b).unwrap();
554 }
555 assert_eq!(s1, s2);
556 }
557
558 #[test]
559 fn empty() { check_encoding(b""); }
560
561 #[test]
562 fn single() { check_encoding(b"*"); }
563
564 #[test]
565 fn two() { check_encoding(b"*x"); }
566
567 #[test]
568 fn just_below_boundary() { check_encoding(&[42; 512]); }
569
570 #[test]
571 fn just_above_boundary() { check_encoding(&[42; 513]); }
572
573 #[test]
574 fn just_above_double_boundary() { check_encoding(&[42; 1025]); }
575
576 #[test]
577 fn fmt_exact_macro() {
578 use crate::alloc::string::ToString;
579
580 struct Dummy([u8; 32]);
581
582 impl fmt::Display for Dummy {
583 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
584 fmt_hex_exact!(f, 32, &self.0, Case::Lower)
585 }
586 }
587 let dummy = Dummy([42; 32]);
588 assert_eq!(dummy.to_string(), "2a".repeat(32));
589 assert_eq!(format!("{:.10}", dummy), "2a".repeat(5));
590 }
591
592 #[test]
593 fn display_short_with_padding() {
594 let v = vec![0xbe, 0xef];
595 assert_eq!(format!("Hello {:<8}!", v.as_hex()), "Hello beef !");
596 assert_eq!(format!("Hello {:-<8}!", v.as_hex()), "Hello beef----!");
597 assert_eq!(format!("Hello {:^8}!", v.as_hex()), "Hello beef !");
598 assert_eq!(format!("Hello {:>8}!", v.as_hex()), "Hello beef!");
599 }
600
601 #[test]
602 fn display_long() {
603 let v = vec![0xab; 512];
605 let mut want = "0".repeat(2000 - 1024);
606 want.extend(core::iter::repeat("ab").take(512));
607 let got = format!("{:0>2000}", v.as_hex());
608 assert_eq!(got, want)
609 }
610
611 #[test]
614 fn precision_truncates() {
615 let v = vec![0x12, 0x34, 0x56, 0x78];
617 assert_eq!(format!("{0:.4}", v.as_hex()), "1234");
619 }
620
621 #[test]
622 fn precision_with_padding_truncates() {
623 let v = vec![0x12, 0x34, 0x56, 0x78];
625 assert_eq!(format!("{0:10.4}", v.as_hex()), "1234 ");
626 }
627
628 #[test]
629 fn precision_with_padding_pads_right() {
630 let v = vec![0x12, 0x34, 0x56, 0x78];
631 assert_eq!(format!("{0:10.20}", v.as_hex()), "12345678 ");
632 }
633
634 #[test]
635 fn precision_with_padding_pads_left() {
636 let v = vec![0x12, 0x34, 0x56, 0x78];
637 assert_eq!(format!("{0:>10.20}", v.as_hex()), " 12345678");
638 }
639
640 #[test]
641 fn precision_with_padding_pads_center() {
642 let v = vec![0x12, 0x34, 0x56, 0x78];
643 assert_eq!(format!("{0:^10.20}", v.as_hex()), " 12345678 ");
644 }
645
646 #[test]
647 fn precision_with_padding_pads_center_odd() {
648 let v = vec![0x12, 0x34, 0x56, 0x78];
649 assert_eq!(format!("{0:^11.20}", v.as_hex()), " 12345678 ");
650 }
651
652 #[test]
653 fn precision_does_not_extend() {
654 let v = vec![0x12, 0x34, 0x56, 0x78];
655 assert_eq!(format!("{0:.16}", v.as_hex()), "12345678");
656 }
657
658 #[test]
659 fn padding_extends() {
660 let v = vec![0xab; 2];
661 assert_eq!(format!("{:0>8}", v.as_hex()), "0000abab");
662 }
663
664 #[test]
665 fn padding_does_not_truncate() {
666 let v = vec![0x12, 0x34, 0x56, 0x78];
667 assert_eq!(format!("{:0>4}", v.as_hex()), "12345678");
668 }
669
670 #[test]
671 fn hex_fmt_impl_macro_forward() {
672 struct Wrapper([u8; 4]);
673
674 impl Borrow<[u8]> for Wrapper {
675 fn borrow(&self) -> &[u8] { &self.0[..] }
676 }
677
678 impl_fmt_traits! {
679 #[display_backward(false)]
680 impl fmt_traits for Wrapper {
681 const LENGTH: usize = 4;
682 }
683 }
684
685 let tc = Wrapper([0x12, 0x34, 0x56, 0x78]);
686
687 let want = "12345678";
688 let got = format!("{}", tc);
689 assert_eq!(got, want);
690 }
691
692 #[test]
693 fn hex_fmt_impl_macro_backwards() {
694 struct Wrapper([u8; 4]);
695
696 impl Borrow<[u8]> for Wrapper {
697 fn borrow(&self) -> &[u8] { &self.0[..] }
698 }
699
700 impl_fmt_traits! {
701 #[display_backward(true)]
702 impl fmt_traits for Wrapper {
703 const LENGTH: usize = 4;
704 }
705 }
706
707 let tc = Wrapper([0x12, 0x34, 0x56, 0x78]);
708
709 let want = "78563412";
710 let got = format!("{}", tc);
711 assert_eq!(got, want);
712 }
713
714 #[test]
715 fn hex_fmt_impl_macro_gen_forward() {
716 struct Wrapper<T>([u8; 4], PhantomData<T>);
717
718 impl<T: Clone> Borrow<[u8]> for Wrapper<T> {
719 fn borrow(&self) -> &[u8] { &self.0[..] }
720 }
721
722 impl_fmt_traits! {
723 #[display_backward(false)]
724 impl<T: Clone> fmt_traits for Wrapper<T> {
725 const LENGTH: usize = 4;
726 }
727 }
728
729 let tc = Wrapper([0x12, 0x34, 0x56, 0x78], PhantomData::<u32>);
731
732 let want = "12345678";
733 let got = format!("{}", tc);
734 assert_eq!(got, want);
735 }
736
737 #[test]
738 fn hex_fmt_impl_macro_gen_backwards() {
739 struct Wrapper<T>([u8; 4], PhantomData<T>);
740
741 impl<T: Clone> Borrow<[u8]> for Wrapper<T> {
742 fn borrow(&self) -> &[u8] { &self.0[..] }
743 }
744
745 impl_fmt_traits! {
746 #[display_backward(true)]
747 impl<T: Clone> fmt_traits for Wrapper<T> {
748 const LENGTH: usize = 4;
749 }
750 }
751
752 let tc = Wrapper([0x12, 0x34, 0x56, 0x78], PhantomData::<u32>);
754
755 let want = "78563412";
756 let got = format!("{}", tc);
757 assert_eq!(got, want);
758 }
759 }
760}