Skip to content

Commit

Permalink
fix: count characters correctly in invalid_hex_error
Browse files Browse the repository at this point in the history
  • Loading branch information
DaniPopes committed Mar 11, 2024
1 parent 9a057f2 commit 7cb862c
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 18 deletions.
14 changes: 7 additions & 7 deletions src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,11 +28,11 @@ impl fmt::Display for FromHexError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
FromHexError::InvalidHexCharacter { c, index } => {
write!(f, "Invalid character {c:?} at position {index}")
Self::InvalidHexCharacter { c, index } => {
write!(f, "invalid character {c:?} at position {index}")
}
FromHexError::OddLength => f.write_str("Odd number of digits"),
FromHexError::InvalidStringLength => f.write_str("Invalid string length"),
Self::OddLength => f.write_str("odd number of digits"),
Self::InvalidStringLength => f.write_str("invalid string length"),
}
}
}
Expand All @@ -46,13 +46,13 @@ mod tests {
fn test_display() {
assert_eq!(
FromHexError::InvalidHexCharacter { c: '\n', index: 5 }.to_string(),
"Invalid character '\\n' at position 5"
"invalid character '\\n' at position 5"
);

assert_eq!(FromHexError::OddLength.to_string(), "Odd number of digits");
assert_eq!(FromHexError::OddLength.to_string(), "odd number of digits");
assert_eq!(
FromHexError::InvalidStringLength.to_string(),
"Invalid string length"
"invalid string length"
);
}
}
20 changes: 13 additions & 7 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -362,11 +362,15 @@ pub fn check<T: AsRef<[u8]>>(input: T) -> Result<(), FromHexError> {
if input.len() % 2 != 0 {
return Err(FromHexError::OddLength);
}
let input = strip_prefix(input);
if imp::check(input) {
let stripped = strip_prefix(input);
if imp::check(stripped) {
Ok(())
} else {
Err(unsafe { invalid_hex_error(input) })
let mut e = unsafe { invalid_hex_error(stripped) };
if let FromHexError::InvalidHexCharacter { ref mut index, .. } = e {
*index += input.len() - stripped.len();
}
Err(e)
}
}

Expand Down Expand Up @@ -667,14 +671,16 @@ const fn strip_prefix(bytes: &[u8]) -> &[u8] {
/// Assumes `input` contains at least one invalid character.
#[cold]
#[cfg_attr(debug_assertions, track_caller)]
const unsafe fn invalid_hex_error(mut input: &[u8]) -> FromHexError {
const unsafe fn invalid_hex_error(input: &[u8]) -> FromHexError {
// Find the first invalid character.
let mut index = None;
while let [byte, rest @ ..] = input {
let mut iter = input;
while let [byte, rest @ ..] = iter {
if HEX_DECODE_LUT[*byte as usize] == NIL {
index = Some(input.len() - rest.len());
index = Some(input.len() - rest.len() - 1);
break;
}
input = rest;
iter = rest;
}

let index = match index {
Expand Down
8 changes: 4 additions & 4 deletions src/traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ impl<T: FromHex> FromHex for Box<T> {

#[inline]
fn from_hex<U: AsRef<[u8]>>(hex: U) -> Result<Self, Self::Error> {
FromHex::from_hex(hex.as_ref()).map(Box::new)
FromHex::from_hex(hex.as_ref()).map(Self::new)
}
}

Expand All @@ -201,7 +201,7 @@ impl<T: FromHex> FromHex for Rc<T> {

#[inline]
fn from_hex<U: AsRef<[u8]>>(hex: U) -> Result<Self, Self::Error> {
FromHex::from_hex(hex.as_ref()).map(Rc::new)
FromHex::from_hex(hex.as_ref()).map(Self::new)
}
}

Expand All @@ -211,7 +211,7 @@ impl<T: FromHex> FromHex for Arc<T> {

#[inline]
fn from_hex<U: AsRef<[u8]>>(hex: U) -> Result<Self, Self::Error> {
FromHex::from_hex(hex.as_ref()).map(Arc::new)
FromHex::from_hex(hex.as_ref()).map(Self::new)
}
}

Expand All @@ -233,7 +233,7 @@ impl FromHex for Vec<i8> {
fn from_hex<T: AsRef<[u8]>>(hex: T) -> Result<Self, Self::Error> {
// SAFETY: transmuting `u8` to `i8` is safe.
crate::decode(hex.as_ref())
.map(|vec| unsafe { core::mem::transmute::<Vec<u8>, Vec<i8>>(vec) })
.map(|vec| unsafe { core::mem::transmute::<Vec<u8>, Self>(vec) })
}
}

Expand Down
21 changes: 21 additions & 0 deletions tests/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,27 @@ fn decode_upper() {
assert_eq!(decoded, ALL);
}

#[test]
fn check() {
assert_eq!(const_hex::check(ALL_LOWER), Ok(()));
assert_eq!(const_hex::check(ALL_UPPER), Ok(()));
assert!(const_hex::check_raw(ALL_LOWER));
assert!(const_hex::check_raw(ALL_UPPER));

let error_cases = [
("ag", 1, 'g'),
("0xbz", 3, 'z'),
("0x12340000000n", 13, 'n'),
];
for (s, index, c) in error_cases {
assert_eq!(s[index..].chars().next(), Some(c), "{s:?}");
assert_eq!(
const_hex::check(s),
Err(const_hex::FromHexError::InvalidHexCharacter { c, index })
);
}
}

#[test]
#[cfg(all(feature = "serde", feature = "alloc", not(feature = "hex")))]
fn serde() {
Expand Down

0 comments on commit 7cb862c

Please sign in to comment.