Skip to content

Commit a44db9f

Browse files
Port hex_string_to_int from C to Rust and support uppercase hex (#2141)
1 parent e4bcade commit a44db9f

5 files changed

Lines changed: 97 additions & 0 deletions

File tree

src/lib_ccx/utility.c

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,6 +269,13 @@ void sleep_secs(int secs)
269269
#endif
270270
}
271271

272+
#ifndef DISABLE_RUST
273+
extern int ccxr_hex_to_int(char high, char low);
274+
int hex_to_int(char high, char low)
275+
{
276+
return ccxr_hex_to_int(high, low);
277+
}
278+
#else
272279
int hex_to_int(char high, char low)
273280
{
274281
unsigned char h, l;
@@ -286,6 +293,15 @@ int hex_to_int(char high, char low)
286293
return -1;
287294
return h * 16 + l;
288295
}
296+
#endif
297+
298+
#ifndef DISABLE_RUST
299+
extern int ccxr_hex_string_to_int(const char *string, int len);
300+
int hex_string_to_int(char *string, int len)
301+
{
302+
return ccxr_hex_string_to_int(string, len);
303+
}
304+
#else
289305
int hex_string_to_int(char *string, int len)
290306
{
291307
int total_return = 0;
@@ -302,6 +318,7 @@ int hex_string_to_int(char *string, int len)
302318
}
303319
return total_return;
304320
}
321+
#endif
305322

306323
#ifndef _WIN32
307324
void m_signal(int sig, void (*func)(int))

src/rust/lib_ccxr/src/util/hex.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
/// Converts a single hex character to its integer value.
2+
/// Returns None if the character is not valid (0-9, a-f, or A-F).
3+
fn hex_char_to_val(c: char) -> Option<i32> {
4+
match c {
5+
'0'..='9' => Some(c as i32 - '0' as i32),
6+
'a'..='f' => Some(c as i32 - 'a' as i32 + 10),
7+
'A'..='F' => Some(c as i32 - 'A' as i32 + 10),
8+
_ => None,
9+
}
10+
}
11+
12+
/// Converts two hex characters into a combined integer value.
13+
/// Returns None if either character is invalid.
14+
pub fn hex_to_int(high: char, low: char) -> Option<i32> {
15+
let h = hex_char_to_val(high)?;
16+
let l = hex_char_to_val(low)?;
17+
Some(h * 16 + l)
18+
}
19+
20+
pub fn hex_string_to_int(string: &str, len: usize) -> Option<i32> {
21+
let mut result = 0;
22+
for c in string.chars().take(len) {
23+
result = result * 16 + hex_char_to_val(c)?;
24+
}
25+
Some(result)
26+
}
27+
28+
#[cfg(test)]
29+
mod tests {
30+
use super::*;
31+
32+
#[test]
33+
fn test_hex_to_int() {
34+
assert_eq!(hex_to_int('4', 'f'), Some(79));
35+
assert_eq!(hex_to_int('0', '0'), Some(0));
36+
assert_eq!(hex_to_int('f', 'f'), Some(255));
37+
assert_eq!(hex_to_int('A', 'F'), Some(175));
38+
assert_eq!(hex_to_int('z', '1'), None);
39+
}
40+
41+
#[test]
42+
fn test_hex_string_to_int() {
43+
assert_eq!(hex_string_to_int("4f", 2), Some(79));
44+
assert_eq!(hex_string_to_int("ff", 2), Some(255));
45+
assert_eq!(hex_string_to_int("00", 2), Some(0));
46+
assert_eq!(hex_string_to_int("ffff", 4), Some(65535));
47+
assert_eq!(hex_string_to_int("4f", 1), Some(4));
48+
assert_eq!(hex_string_to_int("FF", 2), Some(255));
49+
assert_eq!(hex_string_to_int("zz", 2), None);
50+
}
51+
}

src/rust/lib_ccxr/src/util/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
pub mod bits;
1414
pub mod encoders_helper;
1515
pub mod encoding;
16+
pub mod hex;
1617
pub mod levenshtein;
1718
pub mod log;
1819
pub mod time;

src/rust/src/libccxr_exports/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,3 +129,4 @@ pub unsafe extern "C" fn ccxr_levenshtein_dist_char(
129129

130130
ans.min(c_int::MAX as usize) as c_int
131131
}
132+
pub mod util;
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
use std::ffi::{c_char, c_int};
2+
3+
/// Rust equivalent for `hex_to_int` function in C. Uses C-native types as input and output.
4+
///
5+
/// # Safety
6+
///
7+
/// `high` and `low` must be valid ASCII characters. Invalid characters will
8+
/// return -1 rather than causing undefined behavior.
9+
#[no_mangle]
10+
pub unsafe extern "C" fn ccxr_hex_to_int(high: c_char, low: c_char) -> c_int {
11+
lib_ccxr::util::hex::hex_to_int(high as u8 as char, low as u8 as char).unwrap_or(-1)
12+
}
13+
14+
/// Rust equivalent for `hex_string_to_int` function in C. Uses C-native types as input and output.
15+
///
16+
/// # Safety
17+
///
18+
/// `string` must be a valid null-terminated C string. If null, returns -1.
19+
/// Invalid hex characters will return -1 rather than causing undefined behavior.
20+
#[no_mangle]
21+
pub unsafe extern "C" fn ccxr_hex_string_to_int(string: *const c_char, len: c_int) -> c_int {
22+
if string.is_null() {
23+
return -1;
24+
}
25+
let s = std::ffi::CStr::from_ptr(string).to_str().unwrap_or("");
26+
lib_ccxr::util::hex::hex_string_to_int(s, len as usize).unwrap_or(-1)
27+
}

0 commit comments

Comments
 (0)