1use hex::FromHexError;
2use thiserror::Error;
3
4#[derive(Error, Debug)]
5pub enum ConversionError {
6 #[error("Invalid hexadecimal string: {0}")]
7 InvalidHex(#[from] FromHexError),
8 #[error("Incorrect hexadecimal string length: expected {expected}, got {found}")]
9 IncorrectLength { expected: usize, found: usize },
10 #[error("Failed to convert bytes to target integer type")]
11 ConversionFailed,
12}
13
14fn hex_to_bytes_vec(hex_str: &str, expected_len: usize) -> Result<Vec<u8>, ConversionError> {
15 let bytes = hex::decode(hex_str)?;
16 if bytes.len() != expected_len {
17 return Err(ConversionError::IncorrectLength {
18 expected: expected_len,
19 found: bytes.len(),
20 });
21 }
22 Ok(bytes)
23}
24
25#[allow(clippy::needless_question_mark)]
27fn hex_to_bytes<const N: usize>(hex_str: &str) -> Result<[u8; N], ConversionError> {
28 let bytes_vec = hex_to_bytes_vec(hex_str, N)?;
29 Ok(bytes_vec
30 .try_into()
31 .map_err(|_| ConversionError::ConversionFailed)?)
32}
33
34pub fn hex_to_i8(hex_str: &str) -> Result<i8, ConversionError> {
35 let bytes: [u8; 1] = hex_to_bytes(hex_str)?;
36 Ok(i8::from_be_bytes(bytes))
37}
38
39pub fn hex_to_u8(hex_str: &str) -> Result<u8, ConversionError> {
40 let bytes: [u8; 1] = hex_to_bytes(hex_str)?;
41 Ok(u8::from_be_bytes(bytes))
42}
43
44pub fn hex_to_i16_be(hex_str: &str) -> Result<i16, ConversionError> {
45 let bytes: [u8; 2] = hex_to_bytes(hex_str)?;
46 Ok(i16::from_be_bytes(bytes))
47}
48
49pub fn hex_to_i16_le(hex_str: &str) -> Result<i16, ConversionError> {
50 let bytes: [u8; 2] = hex_to_bytes(hex_str)?;
51 Ok(i16::from_le_bytes(bytes))
52}
53
54pub fn hex_to_u16_be(hex_str: &str) -> Result<u16, ConversionError> {
55 let bytes: [u8; 2] = hex_to_bytes(hex_str)?;
56 Ok(u16::from_be_bytes(bytes))
57}
58
59pub fn hex_to_u16_le(hex_str: &str) -> Result<u16, ConversionError> {
60 let bytes: [u8; 2] = hex_to_bytes(hex_str)?;
61 Ok(u16::from_le_bytes(bytes))
62}
63
64pub fn hex_to_i32_be(hex_str: &str) -> Result<i32, ConversionError> {
65 let bytes: [u8; 4] = hex_to_bytes(hex_str)?;
66 Ok(i32::from_be_bytes(bytes))
67}
68
69pub fn hex_to_i32_le(hex_str: &str) -> Result<i32, ConversionError> {
70 let bytes: [u8; 4] = hex_to_bytes(hex_str)?;
71 Ok(i32::from_le_bytes(bytes))
72}
73
74pub fn hex_to_u32_be(hex_str: &str) -> Result<u32, ConversionError> {
75 let bytes: [u8; 4] = hex_to_bytes(hex_str)?;
76 Ok(u32::from_be_bytes(bytes))
77}
78
79pub fn hex_to_u32_le(hex_str: &str) -> Result<u32, ConversionError> {
80 let bytes: [u8; 4] = hex_to_bytes(hex_str)?;
81 Ok(u32::from_le_bytes(bytes))
82}
83
84pub fn hex_to_i64_be(hex_str: &str) -> Result<i64, ConversionError> {
85 let bytes: [u8; 8] = hex_to_bytes(hex_str)?;
86 Ok(i64::from_be_bytes(bytes))
87}
88
89pub fn hex_to_i64_le(hex_str: &str) -> Result<i64, ConversionError> {
90 let bytes: [u8; 8] = hex_to_bytes(hex_str)?;
91 Ok(i64::from_le_bytes(bytes))
92}
93
94pub fn hex_to_u64_be(hex_str: &str) -> Result<u64, ConversionError> {
95 let bytes: [u8; 8] = hex_to_bytes(hex_str)?;
96 Ok(u64::from_be_bytes(bytes))
97}
98
99pub fn hex_to_u64_le(hex_str: &str) -> Result<u64, ConversionError> {
100 let bytes: [u8; 8] = hex_to_bytes(hex_str)?;
101 Ok(u64::from_le_bytes(bytes))
102}
103
104pub fn hex_to_i128_be(hex_str: &str) -> Result<i128, ConversionError> {
105 let bytes: [u8; 16] = hex_to_bytes(hex_str)?;
106 Ok(i128::from_be_bytes(bytes))
107}
108
109pub fn hex_to_i128_le(hex_str: &str) -> Result<i128, ConversionError> {
110 let bytes: [u8; 16] = hex_to_bytes(hex_str)?;
111 Ok(i128::from_le_bytes(bytes))
112}
113
114pub fn hex_to_u128_be(hex_str: &str) -> Result<u128, ConversionError> {
115 let bytes: [u8; 16] = hex_to_bytes(hex_str)?;
116 Ok(u128::from_be_bytes(bytes))
117}
118
119pub fn hex_to_u128_le(hex_str: &str) -> Result<u128, ConversionError> {
120 let bytes: [u8; 16] = hex_to_bytes(hex_str)?;
121 Ok(u128::from_le_bytes(bytes))
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn test_hex_to_i8_valid() {
130 assert_eq!(hex_to_i8("00").unwrap(), 0);
131 assert_eq!(hex_to_i8("7f").unwrap(), 127);
132 assert_eq!(hex_to_i8("80").unwrap(), -128);
133 assert_eq!(hex_to_i8("ff").unwrap(), -1);
134 }
135
136 #[test]
137 fn test_hex_to_u8_valid() {
138 assert_eq!(hex_to_u8("00").unwrap(), 0);
139 assert_eq!(hex_to_u8("7f").unwrap(), 127);
140 assert_eq!(hex_to_u8("80").unwrap(), 128);
141 assert_eq!(hex_to_u8("ff").unwrap(), 255);
142 }
143
144 #[test]
145 fn test_hex_to_i16_be_valid() {
146 assert_eq!(hex_to_i16_be("0000").unwrap(), 0);
147 assert_eq!(hex_to_i16_be("7fff").unwrap(), 32767);
148 assert_eq!(hex_to_i16_be("8000").unwrap(), -32768);
149 assert_eq!(hex_to_i16_be("ffff").unwrap(), -1);
150 }
151
152 #[test]
153 fn test_hex_to_i16_le_valid() {
154 assert_eq!(hex_to_i16_le("0000").unwrap(), 0);
155 assert_eq!(hex_to_i16_le("ff7f").unwrap(), 32767); assert_eq!(hex_to_i16_le("0080").unwrap(), -32768); assert_eq!(hex_to_i16_le("ffff").unwrap(), -1);
158 }
159
160 #[test]
161 fn test_hex_to_u16_be_valid() {
162 assert_eq!(hex_to_u16_be("0000").unwrap(), 0);
163 assert_eq!(hex_to_u16_be("7fff").unwrap(), 32767);
164 assert_eq!(hex_to_u16_be("8000").unwrap(), 32768);
165 assert_eq!(hex_to_u16_be("ffff").unwrap(), 65535);
166 }
167
168 #[test]
169 fn test_hex_to_u16_le_valid() {
170 assert_eq!(hex_to_u16_le("0000").unwrap(), 0);
171 assert_eq!(hex_to_u16_le("ff7f").unwrap(), 32767); assert_eq!(hex_to_u16_le("0080").unwrap(), 32768); assert_eq!(hex_to_u16_le("ffff").unwrap(), 65535);
174 }
175
176 #[test]
177 fn test_hex_to_i32_be_valid() {
178 assert_eq!(hex_to_i32_be("00000000").unwrap(), 0);
179 assert_eq!(hex_to_i32_be("7fffffff").unwrap(), 2147483647);
180 assert_eq!(hex_to_i32_be("80000000").unwrap(), -2147483648);
181 assert_eq!(hex_to_i32_be("ffffffff").unwrap(), -1);
182 }
183
184 #[test]
185 fn test_hex_to_i32_le_valid() {
186 assert_eq!(hex_to_i32_le("00000000").unwrap(), 0);
187 assert_eq!(hex_to_i32_le("ffffff7f").unwrap(), 2147483647); assert_eq!(hex_to_i32_le("00000080").unwrap(), -2147483648); assert_eq!(hex_to_i32_le("ffffffff").unwrap(), -1);
190 }
191
192 #[test]
193 fn test_hex_to_u32_be_valid() {
194 assert_eq!(hex_to_u32_be("00000000").unwrap(), 0);
195 assert_eq!(hex_to_u32_be("7fffffff").unwrap(), 2147483647);
196 assert_eq!(hex_to_u32_be("80000000").unwrap(), 2147483648);
197 assert_eq!(hex_to_u32_be("ffffffff").unwrap(), 4294967295);
198 }
199
200 #[test]
201 fn test_hex_to_u32_le_valid() {
202 assert_eq!(hex_to_u32_le("00000000").unwrap(), 0);
203 assert_eq!(hex_to_u32_le("ffffff7f").unwrap(), 2147483647); assert_eq!(hex_to_u32_le("00000080").unwrap(), 2147483648); assert_eq!(hex_to_u32_le("ffffffff").unwrap(), 4294967295);
206 }
207
208 #[test]
209 fn test_hex_to_i64_be_valid() {
210 assert_eq!(hex_to_i64_be("0000000000000000").unwrap(), 0);
211 assert_eq!(
212 hex_to_i64_be("7fffffffffffffff").unwrap(),
213 9223372036854775807
214 );
215 assert_eq!(
216 hex_to_i64_be("8000000000000000").unwrap(),
217 -9223372036854775808
218 );
219 assert_eq!(hex_to_i64_be("ffffffffffffffff").unwrap(), -1);
220 }
221
222 #[test]
223 fn test_hex_to_i64_le_valid() {
224 assert_eq!(hex_to_i64_le("0000000000000000").unwrap(), 0);
225 assert_eq!(
226 hex_to_i64_le("ffffffffffffff7f").unwrap(),
227 9223372036854775807
228 ); assert_eq!(
230 hex_to_i64_le("0000000000000080").unwrap(),
231 -9223372036854775808
232 ); assert_eq!(hex_to_i64_le("ffffffffffffffff").unwrap(), -1);
234 }
235
236 #[test]
237 fn test_hex_to_u64_be_valid() {
238 assert_eq!(hex_to_u64_be("0000000000000000").unwrap(), 0);
239 assert_eq!(
240 hex_to_u64_be("7fffffffffffffff").unwrap(),
241 9223372036854775807
242 );
243 assert_eq!(
244 hex_to_u64_be("8000000000000000").unwrap(),
245 9223372036854775808
246 );
247 assert_eq!(
248 hex_to_u64_be("ffffffffffffffff").unwrap(),
249 18446744073709551615
250 );
251 }
252
253 #[test]
254 fn test_hex_to_u64_le_valid() {
255 assert_eq!(hex_to_u64_le("0000000000000000").unwrap(), 0);
256 assert_eq!(
257 hex_to_u64_le("ffffffffffffff7f").unwrap(),
258 9223372036854775807
259 ); assert_eq!(
261 hex_to_u64_le("0000000000000080").unwrap(),
262 9223372036854775808
263 ); assert_eq!(
265 hex_to_u64_le("ffffffffffffffff").unwrap(),
266 18446744073709551615
267 );
268 }
269
270 #[test]
271 fn test_invalid_hex_string() {
272 assert!(matches!(
273 hex_to_i8("gg").unwrap_err(),
274 ConversionError::InvalidHex(_)
275 ));
276 assert!(matches!(
277 hex_to_u64_be("nothex").unwrap_err(),
278 ConversionError::InvalidHex(_)
279 ));
280 }
281
282 #[test]
283 fn test_incorrect_length() {
284 assert!(matches!(
285 hex_to_i8("0000").unwrap_err(),
286 ConversionError::IncorrectLength {
287 expected: 1,
288 found: 2
289 }
290 ));
291 assert!(matches!(
292 hex_to_u16_be("00").unwrap_err(),
293 ConversionError::IncorrectLength {
294 expected: 2,
295 found: 1
296 }
297 ));
298 assert!(matches!(
299 hex_to_u64_be("0000").unwrap_err(),
300 ConversionError::IncorrectLength {
301 expected: 8,
302 found: 2
303 }
304 ));
305 }
306}