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 {ArrayLength, GenericArray}; 19 use core::cmp::min; 20 use core::fmt; 21 use core::ops::Add; 22 use core::str; 23 use typenum::*; 24 25 static LOWER_CHARS: &'static [u8] = b"0123456789abcdef"; 26 static UPPER_CHARS: &'static [u8] = b"0123456789ABCDEF"; 27 28 impl<T: ArrayLength<u8>> fmt::LowerHex for GenericArray<u8, T> 29 where 30 T: Add<T>, 31 <T as Add<T>>::Output: ArrayLength<u8>, 32 { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result33 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 34 let max_digits = f.precision().unwrap_or_else(|| self.len() * 2); 35 let max_hex = (max_digits >> 1) + (max_digits & 1); 36 37 if T::to_usize() < 1024 { 38 // For small arrays use a stack allocated 39 // buffer of 2x number of bytes 40 let mut res = GenericArray::<u8, Sum<T, T>>::default(); 41 42 for (i, c) in self.iter().take(max_hex).enumerate() { 43 res[i * 2] = LOWER_CHARS[(c >> 4) as usize]; 44 res[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize]; 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 for (i, c) in chunk.iter().enumerate() { 54 buf[i * 2] = LOWER_CHARS[(c >> 4) as usize]; 55 buf[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize]; 56 } 57 let n = min(chunk.len() * 2, digits_left); 58 f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?; 59 digits_left -= n; 60 } 61 } 62 Ok(()) 63 } 64 } 65 66 impl<T: ArrayLength<u8>> fmt::UpperHex for GenericArray<u8, T> 67 where 68 T: Add<T>, 69 <T as Add<T>>::Output: ArrayLength<u8>, 70 { fmt(&self, f: &mut fmt::Formatter) -> fmt::Result71 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { 72 let max_digits = f.precision().unwrap_or_else(|| self.len() * 2); 73 let max_hex = (max_digits >> 1) + (max_digits & 1); 74 75 if T::to_usize() < 1024 { 76 // For small arrays use a stack allocated 77 // buffer of 2x number of bytes 78 let mut res = GenericArray::<u8, Sum<T, T>>::default(); 79 80 for (i, c) in self.iter().take(max_hex).enumerate() { 81 res[i * 2] = UPPER_CHARS[(c >> 4) as usize]; 82 res[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize]; 83 } 84 f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?; 85 } else { 86 // For large array use chunks of up to 1024 bytes (2048 hex chars) 87 let mut buf = [0u8; 2048]; 88 let mut digits_left = max_digits; 89 90 for chunk in self[..max_hex].chunks(1024) { 91 for (i, c) in chunk.iter().enumerate() { 92 buf[i * 2] = UPPER_CHARS[(c >> 4) as usize]; 93 buf[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize]; 94 } 95 let n = min(chunk.len() * 2, digits_left); 96 f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?; 97 digits_left -= n; 98 } 99 } 100 Ok(()) 101 } 102 } 103