rs_hex2int/
lib.rs

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// Helper to convert hex string to a fixed-size byte array
26#[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); // 0x7fff
156        assert_eq!(hex_to_i16_le("0080").unwrap(), -32768); // 0x8000
157        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); // 0x7fff
172        assert_eq!(hex_to_u16_le("0080").unwrap(), 32768); // 0x8000
173        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); // 0x7fffffff
188        assert_eq!(hex_to_i32_le("00000080").unwrap(), -2147483648); // 0x80000000
189        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); // 0x7fffffff
204        assert_eq!(hex_to_u32_le("00000080").unwrap(), 2147483648); // 0x80000000
205        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        ); // 0x7fffffffffffffff
229        assert_eq!(
230            hex_to_i64_le("0000000000000080").unwrap(),
231            -9223372036854775808
232        ); // 0x8000000000000000
233        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        ); // 0x7fffffffffffffff
260        assert_eq!(
261            hex_to_u64_le("0000000000000080").unwrap(),
262            9223372036854775808
263        ); // 0x8000000000000000
264        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}