parse_int: Add hex parsing for u16 and u64
What changed, and why it matters
This commit is a routine code cleanup and feature addition. It adds new helper functions for reading small and medium-sized unsigned integers (u16 and u64) from hexadecimal strings, using the same safe approach already used for u32 and u128. There is no indication of a security bug being fixed or introduced.
No security action required. Treat as a normal feature/refactoring commit.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change refactors existing hex-parsing functions in units/src/parse_int.rs into a private macro (parse_hex_for!) and uses that macro to generate hex_u16/hex_u64 functions alongside the existing hex_u32/hex_u128 functions. The generated code still delegates to the standard library’s from_str_radix(s, 16) and wraps errors in ParseIntError. API snapshot files are updated to list the new public functions. No logic changes were made to prefix handling or error reporting.
Changed components
units/src/parse_int.rsapi/units/all-features.txtapi/units/alloc-only.txtapi/units/no-features.txtInspect captured patch +114 / −92
diff --git a/api/units/all-features.txt b/api/units/all-features.txt
index 8bc005bc..f8753ff6 100644
--- a/api/units/all-features.txt
+++ b/api/units/all-features.txt
@@ -2555,10 +2555,18 @@ pub fn bitcoin_units::parse_int::hex_u128(s: &str) -> core::result::Result<u128,
pub fn bitcoin_units::parse_int::hex_u128_prefixed(s: &str) -> core::result::Result<u128, bitcoin_units::parse_int::PrefixedHexError>
pub fn bitcoin_units::parse_int::hex_u128_unchecked(s: &str) -> core::result::Result<u128, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::hex_u128_unprefixed(s: &str) -> core::result::Result<u128, bitcoin_units::parse_int::UnprefixedHexError>
+pub fn bitcoin_units::parse_int::hex_u16(s: &str) -> core::result::Result<u16, bitcoin_units::parse_int::ParseIntError>
+pub fn bitcoin_units::parse_int::hex_u16_prefixed(s: &str) -> core::result::Result<u16, bitcoin_units::parse_int::PrefixedHexError>
+pub fn bitcoin_units::parse_int::hex_u16_unchecked(s: &str) -> core::result::Result<u16, bitcoin_units::parse_int::ParseIntError>
+pub fn bitcoin_units::parse_int::hex_u16_unprefixed(s: &str) -> core::result::Result<u16, bitcoin_units::parse_int::UnprefixedHexError>
pub fn bitcoin_units::parse_int::hex_u32(s: &str) -> core::result::Result<u32, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::hex_u32_prefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse_int::PrefixedHexError>
pub fn bitcoin_units::parse_int::hex_u32_unchecked(s: &str) -> core::result::Result<u32, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::hex_u32_unprefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse_int::UnprefixedHexError>
+pub fn bitcoin_units::parse_int::hex_u64(s: &str) -> core::result::Result<u64, bitcoin_units::parse_int::ParseIntError>
+pub fn bitcoin_units::parse_int::hex_u64_prefixed(s: &str) -> core::result::Result<u64, bitcoin_units::parse_int::PrefixedHexError>
+pub fn bitcoin_units::parse_int::hex_u64_unchecked(s: &str) -> core::result::Result<u64, bitcoin_units::parse_int::ParseIntError>
+pub fn bitcoin_units::parse_int::hex_u64_unprefixed(s: &str) -> core::result::Result<u64, bitcoin_units::parse_int::UnprefixedHexError>
pub fn bitcoin_units::parse_int::int_from_box<T: bitcoin_units::parse_int::Integer>(s: alloc::boxed::Box<str>) -> core::result::Result<T, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::int_from_str<T: bitcoin_units::parse_int::Integer>(s: &str) -> core::result::Result<T, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::int_from_string<T: bitcoin_units::parse_int::Integer>(s: alloc::string::String) -> core::result::Result<T, bitcoin_units::parse_int::ParseIntError>
diff --git a/api/units/alloc-only.txt b/api/units/alloc-only.txt
index 87f04321..62a5a186 100644
--- a/api/units/alloc-only.txt
+++ b/api/units/alloc-only.txt
@@ -2119,10 +2119,18 @@ pub fn bitcoin_units::parse_int::hex_u128(s: &str) -> core::result::Result<u128,
pub fn bitcoin_units::parse_int::hex_u128_prefixed(s: &str) -> core::result::Result<u128, bitcoin_units::parse_int::PrefixedHexError>
pub fn bitcoin_units::parse_int::hex_u128_unchecked(s: &str) -> core::result::Result<u128, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::hex_u128_unprefixed(s: &str) -> core::result::Result<u128, bitcoin_units::parse_int::UnprefixedHexError>
+pub fn bitcoin_units::parse_int::hex_u16(s: &str) -> core::result::Result<u16, bitcoin_units::parse_int::ParseIntError>
+pub fn bitcoin_units::parse_int::hex_u16_prefixed(s: &str) -> core::result::Result<u16, bitcoin_units::parse_int::PrefixedHexError>
+pub fn bitcoin_units::parse_int::hex_u16_unchecked(s: &str) -> core::result::Result<u16, bitcoin_units::parse_int::ParseIntError>
+pub fn bitcoin_units::parse_int::hex_u16_unprefixed(s: &str) -> core::result::Result<u16, bitcoin_units::parse_int::UnprefixedHexError>
pub fn bitcoin_units::parse_int::hex_u32(s: &str) -> core::result::Result<u32, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::hex_u32_prefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse_int::PrefixedHexError>
pub fn bitcoin_units::parse_int::hex_u32_unchecked(s: &str) -> core::result::Result<u32, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::hex_u32_unprefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse_int::UnprefixedHexError>
+pub fn bitcoin_units::parse_int::hex_u64(s: &str) -> core::result::Result<u64, bitcoin_units::parse_int::ParseIntError>
+pub fn bitcoin_units::parse_int::hex_u64_prefixed(s: &str) -> core::result::Result<u64, bitcoin_units::parse_int::PrefixedHexError>
+pub fn bitcoin_units::parse_int::hex_u64_unchecked(s: &str) -> core::result::Result<u64, bitcoin_units::parse_int::ParseIntError>
+pub fn bitcoin_units::parse_int::hex_u64_unprefixed(s: &str) -> core::result::Result<u64, bitcoin_units::parse_int::UnprefixedHexError>
pub fn bitcoin_units::parse_int::int_from_box<T: bitcoin_units::parse_int::Integer>(s: alloc::boxed::Box<str>) -> core::result::Result<T, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::int_from_str<T: bitcoin_units::parse_int::Integer>(s: &str) -> core::result::Result<T, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::int_from_string<T: bitcoin_units::parse_int::Integer>(s: alloc::string::String) -> core::result::Result<T, bitcoin_units::parse_int::ParseIntError>
diff --git a/api/units/no-features.txt b/api/units/no-features.txt
index f3b0e94d..dc1135c6 100644
--- a/api/units/no-features.txt
+++ b/api/units/no-features.txt
@@ -2059,10 +2059,18 @@ pub fn bitcoin_units::parse_int::hex_u128(s: &str) -> core::result::Result<u128,
pub fn bitcoin_units::parse_int::hex_u128_prefixed(s: &str) -> core::result::Result<u128, bitcoin_units::parse_int::PrefixedHexError>
pub fn bitcoin_units::parse_int::hex_u128_unchecked(s: &str) -> core::result::Result<u128, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::hex_u128_unprefixed(s: &str) -> core::result::Result<u128, bitcoin_units::parse_int::UnprefixedHexError>
+pub fn bitcoin_units::parse_int::hex_u16(s: &str) -> core::result::Result<u16, bitcoin_units::parse_int::ParseIntError>
+pub fn bitcoin_units::parse_int::hex_u16_prefixed(s: &str) -> core::result::Result<u16, bitcoin_units::parse_int::PrefixedHexError>
+pub fn bitcoin_units::parse_int::hex_u16_unchecked(s: &str) -> core::result::Result<u16, bitcoin_units::parse_int::ParseIntError>
+pub fn bitcoin_units::parse_int::hex_u16_unprefixed(s: &str) -> core::result::Result<u16, bitcoin_units::parse_int::UnprefixedHexError>
pub fn bitcoin_units::parse_int::hex_u32(s: &str) -> core::result::Result<u32, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::hex_u32_prefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse_int::PrefixedHexError>
pub fn bitcoin_units::parse_int::hex_u32_unchecked(s: &str) -> core::result::Result<u32, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::parse_int::hex_u32_unprefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse_int::UnprefixedHexError>
+pub fn bitcoin_units::parse_int::hex_u64(s: &str) -> core::result::Result<u64, bitcoin_units::parse_int::ParseIntError>
+pub fn bitcoin_units::parse_int::hex_u64_prefixed(s: &str) -> core::result::Result<u64, bitcoin_units::parse_int::PrefixedHexError>
+pub fn bitcoin_units::parse_int::hex_u64_unchecked(s: &str) -> core::result::Result<u64, bitcoin_units::parse_int::ParseIntError>
+pub fn bitcoin_units::parse_int::hex_u64_unprefixed(s: &str) -> core::result::Result<u64, bitcoin_units::parse_int::UnprefixedHexError>
pub fn bitcoin_units::parse_int::int_from_str<T: bitcoin_units::parse_int::Integer>(s: &str) -> core::result::Result<T, bitcoin_units::parse_int::ParseIntError>
pub fn bitcoin_units::pow::CompactTarget::clone(&self) -> bitcoin_units::pow::CompactTarget
pub fn bitcoin_units::pow::CompactTarget::cmp(&self, other: &bitcoin_units::pow::CompactTarget) -> core::cmp::Ordering
diff --git a/units/src/parse_int.rs b/units/src/parse_int.rs
index 06a751d7..225db3da 100644
--- a/units/src/parse_int.rs
+++ b/units/src/parse_int.rs
@@ -272,103 +272,101 @@ pub fn hex_check_unprefixed(s: &str) -> Result<&str, UnprefixedHexError> {
Ok(s)
}
-/// Parses a `u32` from a hex string.
-///
-/// Input string may or may not contain a `0x` (or `0X`) prefix.
-///
-/// # Errors
-///
-/// If the input string is not a valid hex encoding of a `u32`.
-pub fn hex_u32(s: &str) -> Result<u32, ParseIntError> {
- let unchecked = hex_remove_optional_prefix(s);
- hex_u32_unchecked(unchecked)
-}
-
-/// Parses a `u32` from a prefixed hex string.
-///
-/// # Errors
-///
-/// - If the input string does not contain a `0x` (or `0X`) prefix.
-/// - If the input string is not a valid hex encoding of a `u32`.
-pub fn hex_u32_prefixed(s: &str) -> Result<u32, PrefixedHexError> {
- let checked = hex_remove_prefix(s)?;
- Ok(hex_u32_unchecked(checked)?)
-}
-
-/// Parses a `u32` from an unprefixed hex string.
-///
-/// # Errors
-///
-/// - If the input string contains a `0x` (or `0X`) prefix.
-/// - If the input string is not a valid hex encoding of a `u32`.
-pub fn hex_u32_unprefixed(s: &str) -> Result<u32, UnprefixedHexError> {
- let checked = hex_check_unprefixed(s)?;
- Ok(hex_u32_unchecked(checked)?)
-}
-
-/// Parses a `u32` from an unprefixed hex string without first checking for a prefix.
-///
-/// # Errors
-///
-/// - If the input string contains a `0x` (or `0X`) prefix, returns `InvalidDigit` due to the `x`.
-/// - If the input string is not a valid hex encoding of a `u32`.
-pub fn hex_u32_unchecked(s: &str) -> Result<u32, ParseIntError> {
- u32::from_str_radix(s, 16).map_err(|error| ParseIntError {
- input: s.into(),
- bits: 32,
- is_signed: false,
- source: error,
- })
-}
+/// Macro to generate parsing functions for a given unsigned type
+macro_rules! parse_hex_for {
+ (
+ $int_type:ty, $bits:literal;
+ fn $any_hex_fn:ident();
+ fn $prefix_hex_fn:ident();
+ fn $unprefix_hex_fn:ident();
+ fn $uncheck_hex_fn:ident();
+ ) => {
+ #[doc = "Parses a `"]
+ #[doc = stringify!($int_type)]
+ #[doc = "` from a hex string.\n\n"]
+ #[doc = "Input string may or may not contain a `0x` (or `0X`) prefix.\n\n"]
+ #[doc = "# Errors\n\nIf the input string is not a valid hex encoding of a `"]
+ #[doc = stringify!($int_type)]
+ #[doc = "`."]
+ pub fn $any_hex_fn(s: &str) -> Result<$int_type, ParseIntError> {
+ let unchecked = hex_remove_optional_prefix(s);
+ $uncheck_hex_fn(unchecked)
+ }
-/// Parses a `u128` from a hex string.
-///
-/// Input string may or may not contain a `0x` (or `0X`) prefix.
-///
-/// # Errors
-///
-/// If the input string is not a valid hex encoding of a `u128`.
-pub fn hex_u128(s: &str) -> Result<u128, ParseIntError> {
- let unchecked = hex_remove_optional_prefix(s);
- hex_u128_unchecked(unchecked)
-}
+ #[doc = "Parses a `"]
+ #[doc = stringify!($int_type)]
+ #[doc = "` from a prefixed hex string.\n\n"]
+ #[doc = "# Errors\n\n"]
+ #[doc = "- If the input string does not contain a `0x` (or `0X`) prefix.\n"]
+ #[doc = "- If the input string is not a valid hex encoding of a `"]
+ #[doc = stringify!($int_type)]
+ #[doc = "`."]
+ pub fn $prefix_hex_fn(s: &str) -> Result<$int_type, PrefixedHexError> {
+ let checked = hex_remove_prefix(s)?;
+ Ok($uncheck_hex_fn(checked)?)
+ }
-/// Parses a `u128` from a prefixed hex string.
-///
-/// # Errors
-///
-/// - If the input string does not contain a `0x` (or `0X`) prefix.
-/// - If the input string is not a valid hex encoding of a `u128`.
-pub fn hex_u128_prefixed(s: &str) -> Result<u128, PrefixedHexError> {
- let checked = hex_remove_prefix(s)?;
- Ok(hex_u128_unchecked(checked)?)
-}
+ #[doc = "Parses a `"]
+ #[doc = stringify!($int_type)]
+ #[doc = "` from an unprefixed hex string.\n\n"]
+ #[doc = "# Errors\n\n"]
+ #[doc = "- If the input string contains a `0x` (or `0X`) prefix.\n"]
+ #[doc = "- If the input string is not a valid hex encoding of a `"]
+ #[doc = stringify!($int_type)]
+ #[doc = "`."]
+ pub fn $unprefix_hex_fn(s: &str) -> Result<$int_type, UnprefixedHexError> {
+ let checked = hex_check_unprefixed(s)?;
+ Ok($uncheck_hex_fn(checked)?)
+ }
-/// Parses a `u128` from an unprefixed hex string.
-///
-/// # Errors
-///
-/// - If the input string contains a `0x` (or `0X`) prefix.
-/// - If the input string is not a valid hex encoding of a `u128`.
-pub fn hex_u128_unprefixed(s: &str) -> Result<u128, UnprefixedHexError> {
- let checked = hex_check_unprefixed(s)?;
- Ok(hex_u128_unchecked(checked)?)
+ #[doc = "Parses a `"]
+ #[doc = stringify!($int_type)]
+ #[doc = "` from an unprefixed hex string without first checking for a prefix.\n\n"]
+ #[doc = "# Errors\n\n"]
+ #[doc = "- If the input string contains a `0x` (or `0X`) prefix,"]
+ #[doc = " returns `InvalidDigit` due to the `x`.\n"]
+ #[doc = "- If the input string is not a valid hex encoding of a `"]
+ #[doc = stringify!($int_type)]
+ #[doc = "`."]
+ pub fn $uncheck_hex_fn(s: &str) -> Result<$int_type, ParseIntError> {
+ <$int_type>::from_str_radix(s, 16).map_err(|error| ParseIntError {
+ input: s.into(),
+ bits: $bits,
+ is_signed: false,
+ source: error,
+ })
+ }
+ };
}
-/// Parses a `u128` from an unprefixed hex string without first checking for a prefix.
-///
-/// # Errors
-///
-/// - If the input string contains a `0x` (or `0X`) prefix, returns `InvalidDigit` due to the `x`.
-/// - If the input string is not a valid hex encoding of a `u128`.
-pub fn hex_u128_unchecked(s: &str) -> Result<u128, ParseIntError> {
- u128::from_str_radix(s, 16).map_err(|error| ParseIntError {
- input: s.into(),
- bits: 128,
- is_signed: false,
- source: error,
- })
-}
+parse_hex_for!(
+ u16, 16;
+ fn hex_u16();
+ fn hex_u16_prefixed();
+ fn hex_u16_unprefixed();
+ fn hex_u16_unchecked();
+);
+parse_hex_for!(
+ u32, 32;
+ fn hex_u32();
+ fn hex_u32_prefixed();
+ fn hex_u32_unprefixed();
+ fn hex_u32_unchecked();
+);
+parse_hex_for!(
+ u64, 64;
+ fn hex_u64();
+ fn hex_u64_prefixed();
+ fn hex_u64_unprefixed();
+ fn hex_u64_unchecked();
+);
+parse_hex_for!(
+ u128, 128;
+ fn hex_u128();
+ fn hex_u128_prefixed();
+ fn hex_u128_unprefixed();
+ fn hex_u128_unchecked();
+);
/// Strips the hex prefix off `s` if one is present.
pub(crate) fn hex_remove_optional_prefix(s: &str) -> &str {
Why this scored 15/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.