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