trick_data/services/convert/
from_hex.rs1use std::string::String;
2
3#[derive(Debug, PartialEq)]
4pub enum ConvertError {
5 HexStringToBytes,
6 ToUtf8,
7}
8
9pub trait FromHex {
10 fn hex_to_string(&self) -> Result<String, ConvertError>;
11}
12
13impl FromHex for str {
14 fn hex_to_string(&self) -> Result<String, ConvertError> {
15 let mut data = String::from(self);
16
17 data = remove_delimiters(data);
18
19 let decoded_bytes = match hex::decode(data) {
20 Ok(decoded_bytes) => decoded_bytes,
21 Err(_) => return Err(ConvertError::HexStringToBytes),
22 };
23
24 return match std::str::from_utf8(&decoded_bytes) {
25 Ok(decoded_data) => Ok(decoded_data.to_string()),
26 Err(_) => return Err(ConvertError::ToUtf8),
27 }
28 }
29}
30
31fn remove_delimiters(data: String) -> String {
32 data.replace(" ", "")
33}
34
35#[cfg(test)]
36mod test {
37 use super::{FromHex, ConvertError};
38 use std::string::String;
39
40 macro_rules! positive_tests {
42 ($($name:ident: $value:expr,)*) => {
43 $(
44 #[test]
45 fn $name() {
46 let (input_data, expected) = $value;
48
49 let actual = input_data.hex_to_string().unwrap();
51
52 assert_eq!(actual, expected)
54 }
55 )*
56 }
57 }
58
59 macro_rules! negative_tests {
61 ($($name:ident: $values:expr,)*) => {
62 $(
63 #[test]
64 fn $name() {
65 let (input_data, expected) = $values;
67
68 let actual = input_data.hex_to_string().unwrap_err();
70
71 assert_eq!(actual, expected)
73 }
74 )*
75 }
76 }
77
78 positive_tests! {
79 empty_string: (String::new(), ""),
80 digits: ("30 31 32 33 34 35 36 37 38 39", "0123456789"),
81 lowercase_ascii: (
82 "61 62 63 64 65 66 67 68 69 6a 6b 6c 6d 6e 6f 70 71 72 73 74 75 76 77 78 79 7a",
83 "abcdefghijklmnopqrstuvwxyz"),
84 uppercase_ascii: (
85 "41 42 43 44 45 46 47 48 49 4a 4b 4c 4d 4e 4f 50 51 52 53 54 55 56 57 58 59 5a",
86 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"),
87 utf8_1byte_first_code_point: ("00", "\u{0000}"),
88 utf8_1byte_last_code_point: ("7f", "\u{007F}"),
89 utf8_2bytes_first_code_point: ("c2 80", "\u{0080}"),
90 utf8_2bytes_last_code_point: ("df bf", "\u{07FF}"),
91 utf8_3bytes_first_code_point: ("e0 a0 80", "\u{0800}"),
92 utf8_3bytes_last_code_point: ("EF BF BF", "\u{FFFF}"),
93 utf8_4bytes_first_code_point: ("F0 90 80 80", "\u{10000}"),
94 utf8_4bytes_last_code_point: ("F4 8F BF BF", "\u{10FFFF}"),
95 }
96
97 negative_tests!{
98 utf8_neg_1byte_out_of_range: ("80", ConvertError::ToUtf8),
99 utf8_neg_2bytes_out_of_range_to_low: ("c2 7F", ConvertError::ToUtf8),
100 utf8_neg_2bytes_out_of_range_to_high: ("df c0", ConvertError::ToUtf8),
101 utf8_neg_3bytes_out_of_range_to_low: ("e0 a0 7F", ConvertError::ToUtf8),
102 utf8_neg_3bytes_out_of_range_to_high: ("EF BF C0", ConvertError::ToUtf8),
103 utf8_neg_4bytes_out_of_range_to_low: ("F0 90 80 7F", ConvertError::ToUtf8),
104 utf8_neg_4bytes_out_of_range_to_high: ("F4 8F BF C0", ConvertError::ToUtf8),
105
106 hex_neg_odd_char: ("8", ConvertError::HexStringToBytes),
107 hex_neg_invalid_char: ("FG", ConvertError::HexStringToBytes),
108 }
109}