use crate::{Transform, TransformError, TransformerCategory};
#[derive(Debug, Clone, PartialEq, Eq, Default)]
pub struct HexToAscii;
impl Transform for HexToAscii {
fn name(&self) -> &'static str {
"Hex to ASCII"
}
fn id(&self) -> &'static str {
"hex_to_ascii"
}
fn description(&self) -> &'static str {
"Decodes a hexadecimal string into its ASCII representation."
}
fn category(&self) -> TransformerCategory {
TransformerCategory::Decoder
}
fn default_test_input(&self) -> &'static str {
"48656c6c6f"
}
fn transform(&self, input: &str) -> Result<String, TransformError> {
if !input.len().is_multiple_of(2) {
return Err(TransformError::InvalidArgument(
"Input hex string must have an even number of characters".into(),
));
}
let cleaned_input = input.trim().trim_start_matches("0x");
let mut bytes = Vec::with_capacity(cleaned_input.len() / 2);
let mut chars = cleaned_input.chars();
while let (Some(h), Some(l)) = (chars.next(), chars.next()) {
let hex_pair = format!("{}{}", h, l);
match u8::from_str_radix(&hex_pair, 16) {
Ok(byte) => bytes.push(byte),
Err(_) => {
return Err(TransformError::InvalidArgument(
format!("Invalid hex character sequence found: '{}'", hex_pair).into(),
))
}
}
}
String::from_utf8(bytes).map_err(|_| TransformError::Utf8Error)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_hex_to_ascii() {
let transformer = HexToAscii;
assert_eq!(
transformer
.transform(transformer.default_test_input())
.unwrap(),
"Hello"
);
assert_eq!(
transformer.transform("68656c6c6f20776f726c64").unwrap(),
"hello world"
);
assert_eq!(transformer.transform("").unwrap(), "");
assert_eq!(transformer.transform("313233").unwrap(), "123");
}
#[test]
fn test_invalid_hex() {
let transformer = HexToAscii;
assert!(matches!(
transformer.transform("48656c6c6G"),
Err(TransformError::InvalidArgument(_))
));
assert!(matches!(
transformer.transform("48656c6c6"),
Err(TransformError::InvalidArgument(_))
));
}
#[test]
fn test_non_utf8_output() {
let transformer = HexToAscii;
assert!(matches!(
transformer.transform("80"),
Err(TransformError::Utf8Error)
));
assert!(matches!(
transformer.transform("c0"),
Err(TransformError::Utf8Error)
)); }
#[test]
fn test_properties() {
let transformer = HexToAscii;
assert_eq!(transformer.name(), "Hex to ASCII");
assert_eq!(transformer.id(), "hex_to_ascii");
assert_eq!(
transformer.description(),
"Decodes a hexadecimal string into its ASCII representation."
);
assert_eq!(transformer.category(), TransformerCategory::Decoder);
}
}