Merge rust-bitcoin/rust-bitcoin#3905: units: Remove `InputString` from the public API

56286265a5 api: Run just check-api (Tobin C. Harding)
39523ea1f5 units: Remove InputString from the public API (Tobin C. Harding)

Pull request description:

  Currently `InputString` is in the public API of `units` because of the trait bound on `parse::int()`. We can just do the monomorphisisation manually to remove it.

  This patch renames `int` to have three different names, one for `&str` one for `String`, and one for `Box<str>` e.g., `units::parse::int_from_str`.

  Close #3708

ACKs for top commit:
  apoelstra:
    ACK 56286265a55368572c61b03bcb81fe04fb7921c0; successfully ran local tests; this looks great!

Tree-SHA512: 5c16640fe4651fbbafd5e3558d8918414df1bb1579ca64b2256f3c10df410481ae29a77ab89f7a1571bfdd710dc6c6bd8ee9217f2c54eeef06e21ab6ce4aa735
This commit is contained in:
merge-script 2025-01-15 19:20:11 +00:00
commit 87d93891a3
No known key found for this signature in database
GPG Key ID: C588D63CE41B97C1
8 changed files with 65 additions and 35 deletions

View File

@ -1183,7 +1183,9 @@ pub fn bitcoin_units::parse::hex_u32(s: &str) -> core::result::Result<u32, bitco
pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::PrefixedHexError> pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::PrefixedHexError>
pub fn bitcoin_units::parse::hex_u32_unchecked(s: &str) -> core::result::Result<u32, bitcoin_units::parse::ParseIntError> pub fn bitcoin_units::parse::hex_u32_unchecked(s: &str) -> core::result::Result<u32, bitcoin_units::parse::ParseIntError>
pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::UnprefixedHexError> pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::UnprefixedHexError>
pub fn bitcoin_units::parse::int<T: bitcoin_units::parse::Integer, S: core::convert::AsRef<str> + core::convert::Into<bitcoin_internals::error::input_string::InputString>>(s: S) -> core::result::Result<T, bitcoin_units::parse::ParseIntError> pub fn bitcoin_units::parse::int_from_box<T: bitcoin_units::parse::Integer>(s: alloc::boxed::Box<str>) -> core::result::Result<T, bitcoin_units::parse::ParseIntError>
pub fn bitcoin_units::parse::int_from_str<T: bitcoin_units::parse::Integer>(s: &str) -> core::result::Result<T, bitcoin_units::parse::ParseIntError>
pub fn bitcoin_units::parse::int_from_string<T: bitcoin_units::parse::Integer>(s: alloc::string::String) -> core::result::Result<T, bitcoin_units::parse::ParseIntError>
pub fn bitcoin_units::weight::Weight::add(self, rhs: &bitcoin_units::weight::Weight) -> Self::Output pub fn bitcoin_units::weight::Weight::add(self, rhs: &bitcoin_units::weight::Weight) -> Self::Output
pub fn bitcoin_units::weight::Weight::add(self, rhs: bitcoin_units::weight::Weight) -> Self::Output pub fn bitcoin_units::weight::Weight::add(self, rhs: bitcoin_units::weight::Weight) -> Self::Output
pub fn bitcoin_units::weight::Weight::add_assign(&mut self, rhs: &bitcoin_units::weight::Weight) pub fn bitcoin_units::weight::Weight::add_assign(&mut self, rhs: &bitcoin_units::weight::Weight)

View File

@ -1030,7 +1030,9 @@ pub fn bitcoin_units::parse::hex_u32(s: &str) -> core::result::Result<u32, bitco
pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::PrefixedHexError> pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::PrefixedHexError>
pub fn bitcoin_units::parse::hex_u32_unchecked(s: &str) -> core::result::Result<u32, bitcoin_units::parse::ParseIntError> pub fn bitcoin_units::parse::hex_u32_unchecked(s: &str) -> core::result::Result<u32, bitcoin_units::parse::ParseIntError>
pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::UnprefixedHexError> pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::UnprefixedHexError>
pub fn bitcoin_units::parse::int<T: bitcoin_units::parse::Integer, S: core::convert::AsRef<str> + core::convert::Into<bitcoin_internals::error::input_string::InputString>>(s: S) -> core::result::Result<T, bitcoin_units::parse::ParseIntError> pub fn bitcoin_units::parse::int_from_box<T: bitcoin_units::parse::Integer>(s: alloc::boxed::Box<str>) -> core::result::Result<T, bitcoin_units::parse::ParseIntError>
pub fn bitcoin_units::parse::int_from_str<T: bitcoin_units::parse::Integer>(s: &str) -> core::result::Result<T, bitcoin_units::parse::ParseIntError>
pub fn bitcoin_units::parse::int_from_string<T: bitcoin_units::parse::Integer>(s: alloc::string::String) -> core::result::Result<T, bitcoin_units::parse::ParseIntError>
pub fn bitcoin_units::weight::Weight::add(self, rhs: &bitcoin_units::weight::Weight) -> Self::Output pub fn bitcoin_units::weight::Weight::add(self, rhs: &bitcoin_units::weight::Weight) -> Self::Output
pub fn bitcoin_units::weight::Weight::add(self, rhs: bitcoin_units::weight::Weight) -> Self::Output pub fn bitcoin_units::weight::Weight::add(self, rhs: bitcoin_units::weight::Weight) -> Self::Output
pub fn bitcoin_units::weight::Weight::add_assign(&mut self, rhs: &bitcoin_units::weight::Weight) pub fn bitcoin_units::weight::Weight::add_assign(&mut self, rhs: &bitcoin_units::weight::Weight)

View File

@ -986,7 +986,7 @@ pub fn bitcoin_units::parse::hex_u32(s: &str) -> core::result::Result<u32, bitco
pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::PrefixedHexError> pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::PrefixedHexError>
pub fn bitcoin_units::parse::hex_u32_unchecked(s: &str) -> core::result::Result<u32, bitcoin_units::parse::ParseIntError> pub fn bitcoin_units::parse::hex_u32_unchecked(s: &str) -> core::result::Result<u32, bitcoin_units::parse::ParseIntError>
pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::UnprefixedHexError> pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::UnprefixedHexError>
pub fn bitcoin_units::parse::int<T: bitcoin_units::parse::Integer, S: core::convert::AsRef<str> + core::convert::Into<bitcoin_internals::error::input_string::InputString>>(s: S) -> core::result::Result<T, bitcoin_units::parse::ParseIntError> pub fn bitcoin_units::parse::int_from_str<T: bitcoin_units::parse::Integer>(s: &str) -> core::result::Result<T, bitcoin_units::parse::ParseIntError>
pub fn bitcoin_units::weight::Weight::add(self, rhs: &bitcoin_units::weight::Weight) -> Self::Output pub fn bitcoin_units::weight::Weight::add(self, rhs: &bitcoin_units::weight::Weight) -> Self::Output
pub fn bitcoin_units::weight::Weight::add(self, rhs: bitcoin_units::weight::Weight) -> Self::Output pub fn bitcoin_units::weight::Weight::add(self, rhs: bitcoin_units::weight::Weight) -> Self::Output
pub fn bitcoin_units::weight::Weight::add_assign(&mut self, rhs: &bitcoin_units::weight::Weight) pub fn bitcoin_units::weight::Weight::add_assign(&mut self, rhs: &bitcoin_units::weight::Weight)

View File

@ -82,7 +82,7 @@ impl FromStr for WitnessVersion {
type Err = FromStrError; type Err = FromStrError;
fn from_str(s: &str) -> Result<Self, Self::Err> { fn from_str(s: &str) -> Result<Self, Self::Err> {
let version: u8 = parse::int(s)?; let version: u8 = parse::int_from_str(s)?;
Ok(WitnessVersion::try_from(version)?) Ok(WitnessVersion::try_from(version)?)
} }
} }

View File

@ -1214,7 +1214,7 @@ mod tests {
assert_eq!( assert_eq!(
"5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:lol" "5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:lol"
.parse::<OutPoint>(), .parse::<OutPoint>(),
Err(ParseOutPointError::Vout(parse::int::<u32, _>("lol").unwrap_err())) Err(ParseOutPointError::Vout(parse::int_from_str::<u32>("lol").unwrap_err()))
); );
assert_eq!( assert_eq!(

View File

@ -239,8 +239,8 @@ pub mod parse {
#[doc(inline)] #[doc(inline)]
pub use units::parse::{ pub use units::parse::{
hex_check_unprefixed, hex_remove_prefix, hex_u128, hex_u128_unchecked, hex_u128_unprefixed, hex_check_unprefixed, hex_remove_prefix, hex_u128, hex_u128_unchecked, hex_u128_unprefixed,
hex_u32, hex_u32_unchecked, hex_u32_unprefixed, int, ParseIntError, PrefixedHexError, hex_u32, hex_u32_unchecked, hex_u32_unprefixed, int_from_box, int_from_str,
UnprefixedHexError, int_from_string, ParseIntError, PrefixedHexError, UnprefixedHexError,
}; };
} }

View File

@ -424,7 +424,7 @@ fn parse_vout(s: &str) -> Result<u32, ParseOutPointError> {
return Err(ParseOutPointError::VoutNotCanonical); return Err(ParseOutPointError::VoutNotCanonical);
} }
} }
parse::int(s).map_err(ParseOutPointError::Vout) parse::int_from_str(s).map_err(ParseOutPointError::Vout)
} }
/// An error in parsing an [`OutPoint`]. /// An error in parsing an [`OutPoint`].

View File

@ -76,9 +76,28 @@ mod sealed {
/// Parses the input string as an integer returning an error carrying rich context. /// Parses the input string as an integer returning an error carrying rich context.
/// ///
/// If the caller owns `String` or `Box<str>` which is not used later it's better to pass it as /// On error this function allocates to copy the input string into the error return. If the caller
/// owned since it avoids allocation in error case. /// has a `String` or `Box<str>` which is not used later it's better to call
pub fn int<T: Integer, S: AsRef<str> + Into<InputString>>(s: S) -> Result<T, ParseIntError> { /// [`parse::int_from_string`] or [`parse::int_from_box`] respectively.
///
/// [`parse::int_from_string`]: crate::parse::int_from_string
/// [`parse::int_from_box`]: crate::parse::int_from_box
pub fn int_from_str<T: Integer>(s: &str) -> Result<T, ParseIntError> { int(s) }
/// Parses the input string as an integer returning an error carrying rich context.
///
/// On error the input string is moved into the error return without allocating.
#[cfg(feature = "alloc")]
pub fn int_from_string<T: Integer>(s: alloc::string::String) -> Result<T, ParseIntError> { int(s) }
/// Parses the input string as an integer returning an error carrying rich context.
///
/// On error the input string is converted into the error return without allocating.
#[cfg(feature = "alloc")]
pub fn int_from_box<T: Integer>(s: alloc::boxed::Box<str>) -> Result<T, ParseIntError> { int(s) }
// This must be private because we do not want `InputString` to appear in the public API.
fn int<T: Integer, S: AsRef<str> + Into<InputString>>(s: S) -> Result<T, ParseIntError> {
s.as_ref().parse().map_err(|error| { s.as_ref().parse().map_err(|error| {
ParseIntError { ParseIntError {
input: s.into(), input: s.into(),
@ -120,39 +139,46 @@ pub fn int<T: Integer, S: AsRef<str> + Into<InputString>>(s: S) -> Result<T, Par
#[doc(hidden)] // This is an 'internal' macro that should not be used outside of the `rust-bitcoin` crate. #[doc(hidden)] // This is an 'internal' macro that should not be used outside of the `rust-bitcoin` crate.
macro_rules! impl_parse_str_from_int_infallible { macro_rules! impl_parse_str_from_int_infallible {
($to:ident, $inner:ident, $fn:ident) => { ($to:ident, $inner:ident, $fn:ident) => {
$crate::impl_tryfrom_str_from_int_infallible!(&str, $to, $inner, $fn);
#[cfg(feature = "alloc")]
$crate::impl_tryfrom_str_from_int_infallible!(alloc::string::String, $to, $inner, $fn; alloc::boxed::Box<str>, $to, $inner, $fn);
impl $crate::_export::_core::str::FromStr for $to { impl $crate::_export::_core::str::FromStr for $to {
type Err = $crate::parse::ParseIntError; type Err = $crate::parse::ParseIntError;
fn from_str(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Err> { fn from_str(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Err> {
$crate::parse::int::<$inner, &str>(s).map($to::$fn) $crate::_export::_core::convert::TryFrom::try_from(s)
} }
} }
} impl $crate::_export::_core::convert::TryFrom<&str> for $to {
}
/// Implements `TryFrom<$from> for $to` using `parse::int`, mapping the output using infallible
/// conversion function `fn`.
#[macro_export]
#[doc(hidden)] // Helper macro called by `impl_parse_str_from_int_infallible`.
macro_rules! impl_tryfrom_str_from_int_infallible {
($($from:ty, $to:ident, $inner:ident, $fn:ident);*) => {
$(
impl $crate::_export::_core::convert::TryFrom<$from> for $to {
type Error = $crate::parse::ParseIntError; type Error = $crate::parse::ParseIntError;
fn try_from(s: $from) -> $crate::_export::_core::result::Result<Self, Self::Error> { fn try_from(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Error> {
$crate::parse::int::<$inner, $from>(s).map($to::$fn) $crate::parse::int_from_str::<$inner>(s).map($to::$fn)
} }
} }
)*
#[cfg(feature = "alloc")]
impl $crate::_export::_core::convert::TryFrom<alloc::string::String> for $to {
type Error = $crate::parse::ParseIntError;
fn try_from(
s: alloc::string::String,
) -> $crate::_export::_core::result::Result<Self, Self::Error> {
$crate::parse::int_from_string::<$inner>(s).map($to::$fn)
} }
} }
#[cfg(feature = "alloc")]
impl $crate::_export::_core::convert::TryFrom<alloc::boxed::Box<str>> for $to {
type Error = $crate::parse::ParseIntError;
fn try_from(
s: alloc::boxed::Box<str>,
) -> $crate::_export::_core::result::Result<Self, Self::Error> {
$crate::parse::int_from_box::<$inner>(s).map($to::$fn)
}
}
};
}
/// Implements standard parsing traits for `$type` by calling through to `$inner_fn`. /// Implements standard parsing traits for `$type` by calling through to `$inner_fn`.
/// ///
/// Implements: /// Implements:
@ -497,9 +523,9 @@ mod tests {
#[test] #[test]
fn parse_int() { fn parse_int() {
assert!(int::<u8, _>("1").is_ok()); assert!(int_from_str::<u8>("1").is_ok());
let _ = int::<i8, _>("not a number").map_err(|e| assert!(e.is_signed)); let _ = int_from_str::<i8>("not a number").map_err(|e| assert!(e.is_signed));
let _ = int::<u8, _>("not a number").map_err(|e| assert!(!e.is_signed)); let _ = int_from_str::<u8>("not a number").map_err(|e| assert!(!e.is_signed));
} }
#[test] #[test]
@ -520,7 +546,7 @@ mod tests {
fn from(_: i8) -> Self { TestTypeLargerThanU128(0, 0) } fn from(_: i8) -> Self { TestTypeLargerThanU128(0, 0) }
} }
let result = panic::catch_unwind(|| int::<TestTypeLargerThanU128, _>("not a number")); let result = panic::catch_unwind(|| int_from_str::<TestTypeLargerThanU128>("not a number"));
assert!(result.is_err()); assert!(result.is_err());
} }