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