Port hex_string_to_int from C to Rust and support uppercase hex (#2141)

This commit is contained in:
Anayo Anyafulu
2026-03-07 09:55:33 +02:00
committed by GitHub
parent e4bcade799
commit a44db9f617
5 changed files with 97 additions and 0 deletions

View File

@@ -269,6 +269,13 @@ void sleep_secs(int secs)
#endif
}
#ifndef DISABLE_RUST
extern int ccxr_hex_to_int(char high, char low);
int hex_to_int(char high, char low)
{
return ccxr_hex_to_int(high, low);
}
#else
int hex_to_int(char high, char low)
{
unsigned char h, l;
@@ -286,6 +293,15 @@ int hex_to_int(char high, char low)
return -1;
return h * 16 + l;
}
#endif
#ifndef DISABLE_RUST
extern int ccxr_hex_string_to_int(const char *string, int len);
int hex_string_to_int(char *string, int len)
{
return ccxr_hex_string_to_int(string, len);
}
#else
int hex_string_to_int(char *string, int len)
{
int total_return = 0;
@@ -302,6 +318,7 @@ int hex_string_to_int(char *string, int len)
}
return total_return;
}
#endif
#ifndef _WIN32
void m_signal(int sig, void (*func)(int))

View File

@@ -0,0 +1,51 @@
/// Converts a single hex character to its integer value.
/// Returns None if the character is not valid (0-9, a-f, or A-F).
fn hex_char_to_val(c: char) -> Option<i32> {
match c {
'0'..='9' => Some(c as i32 - '0' as i32),
'a'..='f' => Some(c as i32 - 'a' as i32 + 10),
'A'..='F' => Some(c as i32 - 'A' as i32 + 10),
_ => None,
}
}
/// Converts two hex characters into a combined integer value.
/// Returns None if either character is invalid.
pub fn hex_to_int(high: char, low: char) -> Option<i32> {
let h = hex_char_to_val(high)?;
let l = hex_char_to_val(low)?;
Some(h * 16 + l)
}
pub fn hex_string_to_int(string: &str, len: usize) -> Option<i32> {
let mut result = 0;
for c in string.chars().take(len) {
result = result * 16 + hex_char_to_val(c)?;
}
Some(result)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hex_to_int() {
assert_eq!(hex_to_int('4', 'f'), Some(79));
assert_eq!(hex_to_int('0', '0'), Some(0));
assert_eq!(hex_to_int('f', 'f'), Some(255));
assert_eq!(hex_to_int('A', 'F'), Some(175));
assert_eq!(hex_to_int('z', '1'), None);
}
#[test]
fn test_hex_string_to_int() {
assert_eq!(hex_string_to_int("4f", 2), Some(79));
assert_eq!(hex_string_to_int("ff", 2), Some(255));
assert_eq!(hex_string_to_int("00", 2), Some(0));
assert_eq!(hex_string_to_int("ffff", 4), Some(65535));
assert_eq!(hex_string_to_int("4f", 1), Some(4));
assert_eq!(hex_string_to_int("FF", 2), Some(255));
assert_eq!(hex_string_to_int("zz", 2), None);
}
}

View File

@@ -13,6 +13,7 @@
pub mod bits;
pub mod encoders_helper;
pub mod encoding;
pub mod hex;
pub mod levenshtein;
pub mod log;
pub mod time;

View File

@@ -129,3 +129,4 @@ pub unsafe extern "C" fn ccxr_levenshtein_dist_char(
ans.min(c_int::MAX as usize) as c_int
}
pub mod util;

View File

@@ -0,0 +1,27 @@
use std::ffi::{c_char, c_int};
/// Rust equivalent for `hex_to_int` function in C. Uses C-native types as input and output.
///
/// # Safety
///
/// `high` and `low` must be valid ASCII characters. Invalid characters will
/// return -1 rather than causing undefined behavior.
#[no_mangle]
pub unsafe extern "C" fn ccxr_hex_to_int(high: c_char, low: c_char) -> c_int {
lib_ccxr::util::hex::hex_to_int(high as u8 as char, low as u8 as char).unwrap_or(-1)
}
/// Rust equivalent for `hex_string_to_int` function in C. Uses C-native types as input and output.
///
/// # Safety
///
/// `string` must be a valid null-terminated C string. If null, returns -1.
/// Invalid hex characters will return -1 rather than causing undefined behavior.
#[no_mangle]
pub unsafe extern "C" fn ccxr_hex_string_to_int(string: *const c_char, len: c_int) -> c_int {
if string.is_null() {
return -1;
}
let s = std::ffi::CStr::from_ptr(string).to_str().unwrap_or("");
lib_ccxr::util::hex::hex_string_to_int(s, len as usize).unwrap_or(-1)
}