1 //! Generic array are commonly used as a return value for hash digests, so 2 //! it's a good idea to allow to hexlify them easily. This module implements 3 //! `std::fmt::LowerHex` and `std::fmt::UpperHex` traits. 4 //! 5 //! Example: 6 //! 7 //! ```rust 8 //! # #[macro_use] 9 //! # extern crate generic_array; 10 //! # extern crate typenum; 11 //! # fn main() { 12 //! let array = arr![u8; 10, 20, 30]; 13 //! assert_eq!(format!("{:x}", array), "0a141e"); 14 //! # } 15 //! ``` 16 //! 17 18 use core::{fmt, str, ops::Add, cmp::min}; 19 20 use typenum::*; 21 22 use crate::{ArrayLength, GenericArray}; 23 24 static LOWER_CHARS: &'static [u8] = b"0123456789abcdef"; 25 static UPPER_CHARS: &'static [u8] = b"0123456789ABCDEF"; 26 27 impl<T: ArrayLength<u8>> fmt::LowerHex for GenericArray<u8, T> 28 where 29 T: Add<T>, 30 <T as Add<T>>::Output: ArrayLength<u8>, 31 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 33 let max_digits = f.precision().unwrap_or_else(|| self.len() * 2); 34 let max_hex = (max_digits >> 1) + (max_digits & 1); 35 36 if T::USIZE < 1024 { 37 // For small arrays use a stack allocated 38 // buffer of 2x number of bytes 39 let mut res = GenericArray::<u8, Sum<T, T>>::default(); 40 41 self.iter().take(max_hex).enumerate().for_each(|(i, c)| { 42 res[i * 2] = LOWER_CHARS[(c >> 4) as usize]; 43 res[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize]; 44 }); 45 46 f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?; 47 } else { 48 // For large array use chunks of up to 1024 bytes (2048 hex chars) 49 let mut buf = [0u8; 2048]; 50 let mut digits_left = max_digits; 51 52 for chunk in self[..max_hex].chunks(1024) { 53 chunk.iter().enumerate().for_each(|(i, c)| { 54 buf[i * 2] = LOWER_CHARS[(c >> 4) as usize]; 55 buf[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize]; 56 }); 57 58 let n = min(chunk.len() * 2, digits_left); 59 f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?; 60 digits_left -= n; 61 } 62 } 63 Ok(()) 64 } 65 } 66 67 impl<T: ArrayLength<u8>> fmt::UpperHex for GenericArray<u8, T> 68 where 69 T: Add<T>, 70 <T as Add<T>>::Output: ArrayLength<u8>, 71 { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result72 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 73 let max_digits = f.precision().unwrap_or_else(|| self.len() * 2); 74 let max_hex = (max_digits >> 1) + (max_digits & 1); 75 76 if T::USIZE < 1024 { 77 // For small arrays use a stack allocated 78 // buffer of 2x number of bytes 79 let mut res = GenericArray::<u8, Sum<T, T>>::default(); 80 81 self.iter().take(max_hex).enumerate().for_each(|(i, c)| { 82 res[i * 2] = UPPER_CHARS[(c >> 4) as usize]; 83 res[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize]; 84 }); 85 86 f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?; 87 } else { 88 // For large array use chunks of up to 1024 bytes (2048 hex chars) 89 let mut buf = [0u8; 2048]; 90 let mut digits_left = max_digits; 91 92 for chunk in self[..max_hex].chunks(1024) { 93 chunk.iter().enumerate().for_each(|(i, c)| { 94 buf[i * 2] = UPPER_CHARS[(c >> 4) as usize]; 95 buf[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize]; 96 }); 97 98 let n = min(chunk.len() * 2, digits_left); 99 f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?; 100 digits_left -= n; 101 } 102 } 103 Ok(()) 104 } 105 } 106