1#[allow(clippy::missing_panics_doc)]
6pub fn encode<T: AsRef<[u8]>>(bytes: T) -> String {
7 let bytes = bytes.as_ref();
8 let mut encoding = String::with_capacity(2 * bytes.len());
9 for byte in bytes {
10 let upper_val = byte >> 4u8;
11 let lower_val = byte & 0x0f;
12 encoding.push(char::from_digit(u32::from(upper_val), 16).unwrap());
14 encoding.push(char::from_digit(u32::from(lower_val), 16).unwrap());
15 }
16 encoding
17}
18
19pub fn encode_upper<T: AsRef<[u8]>>(bytes: T) -> String {
21 encode(bytes).to_ascii_uppercase()
22}
23
24#[allow(clippy::missing_panics_doc)]
28pub fn decode(hex_str: &str) -> Result<Vec<u8>, String> {
29 let mut bytes = Vec::<u8>::with_capacity(hex_str.len() / 2 + 1);
30 let mut current_byte = b'\0';
31 let mut index: u32 = 0;
32 for ch in hex_str.chars() {
33 if !ch.is_ascii_hexdigit() {
34 return Err("Invalid hex string".to_string());
35 }
36 #[allow(clippy::cast_possible_truncation)]
37 let value = ch.to_digit(16).unwrap() as u8;
40 if index % 2 == 0 {
41 current_byte = value << 4;
42 } else {
43 current_byte |= value;
44 bytes.push(current_byte);
45 }
46
47 if let Some(idx) = index.checked_add(1) {
48 index = idx;
49 } else {
50 break;
51 }
52 }
53 if index % 2 == 1 {
54 bytes.push(current_byte);
55 }
56 Ok(bytes)
57}
58
59#[must_use]
62#[allow(clippy::missing_panics_doc)]
63pub fn decode_dirty(hex_str: &str) -> Vec<u8> {
64 let clean: String = hex_str.chars().filter(char::is_ascii_hexdigit).collect();
65 decode(clean.as_str()).unwrap()
67}