units: Remove InputString from the public API
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>`.
This commit is contained in:
parent
1af293efe3
commit
39523ea1f5
|
@ -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)?)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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!(
|
||||||
|
|
|
@ -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,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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`].
|
||||||
|
|
|
@ -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,37 +139,44 @@ 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`.
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue