Skip to content

Commit 87d9389

Browse files
committed
Merge rust-bitcoin#3905: units: Remove InputString from the public API
5628626 api: Run just check-api (Tobin C. Harding) 39523ea 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 rust-bitcoin#3708 ACKs for top commit: apoelstra: ACK 5628626; successfully ran local tests; this looks great! Tree-SHA512: 5c16640fe4651fbbafd5e3558d8918414df1bb1579ca64b2256f3c10df410481ae29a77ab89f7a1571bfdd710dc6c6bd8ee9217f2c54eeef06e21ab6ce4aa735
2 parents 1af293e + 5628626 commit 87d9389

File tree

8 files changed

+64
-34
lines changed

8 files changed

+64
-34
lines changed

api/units/all-features.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -1183,7 +1183,9 @@ pub fn bitcoin_units::parse::hex_u32(s: &str) -> core::result::Result<u32, bitco
11831183
pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::PrefixedHexError>
11841184
pub fn bitcoin_units::parse::hex_u32_unchecked(s: &str) -> core::result::Result<u32, bitcoin_units::parse::ParseIntError>
11851185
pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::UnprefixedHexError>
1186-
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>
1186+
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>
1187+
pub fn bitcoin_units::parse::int_from_str<T: bitcoin_units::parse::Integer>(s: &str) -> core::result::Result<T, bitcoin_units::parse::ParseIntError>
1188+
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>
11871189
pub fn bitcoin_units::weight::Weight::add(self, rhs: &bitcoin_units::weight::Weight) -> Self::Output
11881190
pub fn bitcoin_units::weight::Weight::add(self, rhs: bitcoin_units::weight::Weight) -> Self::Output
11891191
pub fn bitcoin_units::weight::Weight::add_assign(&mut self, rhs: &bitcoin_units::weight::Weight)

api/units/alloc-only.txt

+3-1
Original file line numberDiff line numberDiff line change
@@ -1030,7 +1030,9 @@ pub fn bitcoin_units::parse::hex_u32(s: &str) -> core::result::Result<u32, bitco
10301030
pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::PrefixedHexError>
10311031
pub fn bitcoin_units::parse::hex_u32_unchecked(s: &str) -> core::result::Result<u32, bitcoin_units::parse::ParseIntError>
10321032
pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::UnprefixedHexError>
1033-
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>
1033+
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>
1034+
pub fn bitcoin_units::parse::int_from_str<T: bitcoin_units::parse::Integer>(s: &str) -> core::result::Result<T, bitcoin_units::parse::ParseIntError>
1035+
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>
10341036
pub fn bitcoin_units::weight::Weight::add(self, rhs: &bitcoin_units::weight::Weight) -> Self::Output
10351037
pub fn bitcoin_units::weight::Weight::add(self, rhs: bitcoin_units::weight::Weight) -> Self::Output
10361038
pub fn bitcoin_units::weight::Weight::add_assign(&mut self, rhs: &bitcoin_units::weight::Weight)

api/units/no-features.txt

+1-1
Original file line numberDiff line numberDiff line change
@@ -986,7 +986,7 @@ pub fn bitcoin_units::parse::hex_u32(s: &str) -> core::result::Result<u32, bitco
986986
pub fn bitcoin_units::parse::hex_u32_prefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::PrefixedHexError>
987987
pub fn bitcoin_units::parse::hex_u32_unchecked(s: &str) -> core::result::Result<u32, bitcoin_units::parse::ParseIntError>
988988
pub fn bitcoin_units::parse::hex_u32_unprefixed(s: &str) -> core::result::Result<u32, bitcoin_units::parse::UnprefixedHexError>
989-
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>
989+
pub fn bitcoin_units::parse::int_from_str<T: bitcoin_units::parse::Integer>(s: &str) -> core::result::Result<T, bitcoin_units::parse::ParseIntError>
990990
pub fn bitcoin_units::weight::Weight::add(self, rhs: &bitcoin_units::weight::Weight) -> Self::Output
991991
pub fn bitcoin_units::weight::Weight::add(self, rhs: bitcoin_units::weight::Weight) -> Self::Output
992992
pub fn bitcoin_units::weight::Weight::add_assign(&mut self, rhs: &bitcoin_units::weight::Weight)

bitcoin/src/blockdata/script/witness_version.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,7 @@ impl FromStr for WitnessVersion {
8282
type Err = FromStrError;
8383

8484
fn from_str(s: &str) -> Result<Self, Self::Err> {
85-
let version: u8 = parse::int(s)?;
85+
let version: u8 = parse::int_from_str(s)?;
8686
Ok(WitnessVersion::try_from(version)?)
8787
}
8888
}

bitcoin/src/blockdata/transaction.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1214,7 +1214,7 @@ mod tests {
12141214
assert_eq!(
12151215
"5df6e0e2761359d30a8275058e299fcc0381534545f55cf43e41983f5d4c9456:lol"
12161216
.parse::<OutPoint>(),
1217-
Err(ParseOutPointError::Vout(parse::int::<u32, _>("lol").unwrap_err()))
1217+
Err(ParseOutPointError::Vout(parse::int_from_str::<u32>("lol").unwrap_err()))
12181218
);
12191219

12201220
assert_eq!(

bitcoin/src/lib.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ pub mod parse {
239239
#[doc(inline)]
240240
pub use units::parse::{
241241
hex_check_unprefixed, hex_remove_prefix, hex_u128, hex_u128_unchecked, hex_u128_unprefixed,
242-
hex_u32, hex_u32_unchecked, hex_u32_unprefixed, int, ParseIntError, PrefixedHexError,
243-
UnprefixedHexError,
242+
hex_u32, hex_u32_unchecked, hex_u32_unprefixed, int_from_box, int_from_str,
243+
int_from_string, ParseIntError, PrefixedHexError, UnprefixedHexError,
244244
};
245245
}
246246

primitives/src/transaction.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -424,7 +424,7 @@ fn parse_vout(s: &str) -> Result<u32, ParseOutPointError> {
424424
return Err(ParseOutPointError::VoutNotCanonical);
425425
}
426426
}
427-
parse::int(s).map_err(ParseOutPointError::Vout)
427+
parse::int_from_str(s).map_err(ParseOutPointError::Vout)
428428
}
429429

430430
/// An error in parsing an [`OutPoint`].

units/src/parse.rs

+52-26
Original file line numberDiff line numberDiff line change
@@ -76,9 +76,28 @@ mod sealed {
7676

7777
/// Parses the input string as an integer returning an error carrying rich context.
7878
///
79-
/// If the caller owns `String` or `Box<str>` which is not used later it's better to pass it as
80-
/// owned since it avoids allocation in error case.
81-
pub fn int<T: Integer, S: AsRef<str> + Into<InputString>>(s: S) -> Result<T, ParseIntError> {
79+
/// On error this function allocates to copy the input string into the error return. If the caller
80+
/// has a `String` or `Box<str>` which is not used later it's better to call
81+
/// [`parse::int_from_string`] or [`parse::int_from_box`] respectively.
82+
///
83+
/// [`parse::int_from_string`]: crate::parse::int_from_string
84+
/// [`parse::int_from_box`]: crate::parse::int_from_box
85+
pub fn int_from_str<T: Integer>(s: &str) -> Result<T, ParseIntError> { int(s) }
86+
87+
/// Parses the input string as an integer returning an error carrying rich context.
88+
///
89+
/// On error the input string is moved into the error return without allocating.
90+
#[cfg(feature = "alloc")]
91+
pub fn int_from_string<T: Integer>(s: alloc::string::String) -> Result<T, ParseIntError> { int(s) }
92+
93+
/// Parses the input string as an integer returning an error carrying rich context.
94+
///
95+
/// On error the input string is converted into the error return without allocating.
96+
#[cfg(feature = "alloc")]
97+
pub fn int_from_box<T: Integer>(s: alloc::boxed::Box<str>) -> Result<T, ParseIntError> { int(s) }
98+
99+
// This must be private because we do not want `InputString` to appear in the public API.
100+
fn int<T: Integer, S: AsRef<str> + Into<InputString>>(s: S) -> Result<T, ParseIntError> {
82101
s.as_ref().parse().map_err(|error| {
83102
ParseIntError {
84103
input: s.into(),
@@ -120,37 +139,44 @@ pub fn int<T: Integer, S: AsRef<str> + Into<InputString>>(s: S) -> Result<T, Par
120139
#[doc(hidden)] // This is an 'internal' macro that should not be used outside of the `rust-bitcoin` crate.
121140
macro_rules! impl_parse_str_from_int_infallible {
122141
($to:ident, $inner:ident, $fn:ident) => {
123-
$crate::impl_tryfrom_str_from_int_infallible!(&str, $to, $inner, $fn);
124-
#[cfg(feature = "alloc")]
125-
$crate::impl_tryfrom_str_from_int_infallible!(alloc::string::String, $to, $inner, $fn; alloc::boxed::Box<str>, $to, $inner, $fn);
126-
127142
impl $crate::_export::_core::str::FromStr for $to {
128143
type Err = $crate::parse::ParseIntError;
129144

130145
fn from_str(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Err> {
131-
$crate::parse::int::<$inner, &str>(s).map($to::$fn)
146+
$crate::_export::_core::convert::TryFrom::try_from(s)
132147
}
133148
}
134149

135-
}
136-
}
150+
impl $crate::_export::_core::convert::TryFrom<&str> for $to {
151+
type Error = $crate::parse::ParseIntError;
137152

138-
/// Implements `TryFrom<$from> for $to` using `parse::int`, mapping the output using infallible
139-
/// conversion function `fn`.
140-
#[macro_export]
141-
#[doc(hidden)] // Helper macro called by `impl_parse_str_from_int_infallible`.
142-
macro_rules! impl_tryfrom_str_from_int_infallible {
143-
($($from:ty, $to:ident, $inner:ident, $fn:ident);*) => {
144-
$(
145-
impl $crate::_export::_core::convert::TryFrom<$from> for $to {
153+
fn try_from(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Error> {
154+
$crate::parse::int_from_str::<$inner>(s).map($to::$fn)
155+
}
156+
}
157+
158+
#[cfg(feature = "alloc")]
159+
impl $crate::_export::_core::convert::TryFrom<alloc::string::String> for $to {
146160
type Error = $crate::parse::ParseIntError;
147161

148-
fn try_from(s: $from) -> $crate::_export::_core::result::Result<Self, Self::Error> {
149-
$crate::parse::int::<$inner, $from>(s).map($to::$fn)
162+
fn try_from(
163+
s: alloc::string::String,
164+
) -> $crate::_export::_core::result::Result<Self, Self::Error> {
165+
$crate::parse::int_from_string::<$inner>(s).map($to::$fn)
150166
}
151167
}
152-
)*
153-
}
168+
169+
#[cfg(feature = "alloc")]
170+
impl $crate::_export::_core::convert::TryFrom<alloc::boxed::Box<str>> for $to {
171+
type Error = $crate::parse::ParseIntError;
172+
173+
fn try_from(
174+
s: alloc::boxed::Box<str>,
175+
) -> $crate::_export::_core::result::Result<Self, Self::Error> {
176+
$crate::parse::int_from_box::<$inner>(s).map($to::$fn)
177+
}
178+
}
179+
};
154180
}
155181

156182
/// Implements standard parsing traits for `$type` by calling through to `$inner_fn`.
@@ -497,9 +523,9 @@ mod tests {
497523

498524
#[test]
499525
fn parse_int() {
500-
assert!(int::<u8, _>("1").is_ok());
501-
let _ = int::<i8, _>("not a number").map_err(|e| assert!(e.is_signed));
502-
let _ = int::<u8, _>("not a number").map_err(|e| assert!(!e.is_signed));
526+
assert!(int_from_str::<u8>("1").is_ok());
527+
let _ = int_from_str::<i8>("not a number").map_err(|e| assert!(e.is_signed));
528+
let _ = int_from_str::<u8>("not a number").map_err(|e| assert!(!e.is_signed));
503529
}
504530

505531
#[test]
@@ -520,7 +546,7 @@ mod tests {
520546
fn from(_: i8) -> Self { TestTypeLargerThanU128(0, 0) }
521547
}
522548

523-
let result = panic::catch_unwind(|| int::<TestTypeLargerThanU128, _>("not a number"));
549+
let result = panic::catch_unwind(|| int_from_str::<TestTypeLargerThanU128>("not a number"));
524550
assert!(result.is_err());
525551
}
526552

0 commit comments

Comments
 (0)