From 88f6621e3082f28c2125837b5eb1e76a1c5ee92a Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Fri, 1 Nov 2024 17:47:22 +1100 Subject: [PATCH 1/4] Split parse macros Done in preparation for enabling no-alloc builds. Split the macro calls to handle `str` separately from `alloc` types. --- units/src/locktime/absolute.rs | 2 -- units/src/parse.rs | 11 ++++++----- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index 92283468d..6f87b21bd 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -2,8 +2,6 @@ //! Provides [`Height`] and [`Time`] types used by the `rust-bitcoin` `absolute::LockTime` type. -#[cfg(feature = "alloc")] -use alloc::{boxed::Box, string::String}; use core::fmt; use internals::error::InputString; diff --git a/units/src/parse.rs b/units/src/parse.rs index a2ee0e4db..52ea0e74b 100644 --- a/units/src/parse.rs +++ b/units/src/parse.rs @@ -107,10 +107,9 @@ macro_rules! impl_tryfrom_str_from_int_infallible { #[macro_export] macro_rules! impl_parse_str_from_int_infallible { ($to:ident, $inner:ident, $fn:ident) => { - #[cfg(all(feature = "alloc", not(feature = "std")))] - $crate::impl_tryfrom_str_from_int_infallible!(&str, $to, $inner, $fn; alloc::string::String, $to, $inner, $fn; alloc::boxed::Box, $to, $inner, $fn); - #[cfg(feature = "std")] - $crate::impl_tryfrom_str_from_int_infallible!(&str, $to, $inner, $fn; std::string::String, $to, $inner, $fn; std::boxed::Box, $to, $inner, $fn); + $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, $to, $inner, $fn); impl core::str::FromStr for $to { type Err = $crate::parse::ParseIntError; @@ -143,7 +142,9 @@ macro_rules! impl_tryfrom_str { #[macro_export] macro_rules! impl_parse_str { ($to:ty, $err:ty, $inner_fn:expr) => { - $crate::impl_tryfrom_str!(&str, $to, $err, $inner_fn; String, $to, $err, $inner_fn; Box, $to, $err, $inner_fn); + $crate::impl_tryfrom_str!(&str, $to, $err, $inner_fn); + #[cfg(feature = "alloc")] + $crate::impl_tryfrom_str!(alloc::string::String, $to, $err, $inner_fn; alloc::boxed::Box, $to, $err, $inner_fn); impl core::str::FromStr for $to { type Err = $err; From ff20249bdc1eb344c00f92503a105e79521aca21 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Fri, 1 Nov 2024 17:49:13 +1100 Subject: [PATCH 2/4] Remove unneeded feature gate We can use the `parse::hex_remove_optional_prefix` now without the feature gate. --- units/src/locktime/absolute.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/units/src/locktime/absolute.rs b/units/src/locktime/absolute.rs index 6f87b21bd..8407eaece 100644 --- a/units/src/locktime/absolute.rs +++ b/units/src/locktime/absolute.rs @@ -6,9 +6,7 @@ use core::fmt; use internals::error::InputString; -use crate::parse::ParseIntError; -#[cfg(feature = "alloc")] -use crate::parse; +use crate::parse::{self, ParseIntError}; /// The Threshold for deciding whether a lock time value is a height or a time (see [Bitcoin Core]). /// From e347b50614ca8813cc562939d548ce7fb311b8bc Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Fri, 1 Nov 2024 17:54:19 +1100 Subject: [PATCH 3/4] Use InputString in hex prefix error types In an effort to reduce requirement for `alloc`; remove the `String` and use `InputString` in the hex prefix related error types. Tested with: (Note in test code we have to use `"cafe".to_owned()` before this patch is applied.) rust``` #[test] fn hex_prefix_errors() { let err = hex_remove_prefix("cafe").unwrap_err(); std::println!("{}", err); std::println!("{:?}", err); let err = hex_check_unprefixed("0xcafe").unwrap_err(); std::println!("{}", err); std::println!("{:?}", err); } ``` Before: hex string is missing a prefix (e.g. 0x): cafe MissingPrefixError { hex: "cafe" } hex string contains a prefix: 0xcafe ContainsPrefixError { hex: "0xcafe" } After: failed to parse 'cafe' as hex because it is missing the '0x' prefix MissingPrefixError { hex: InputString("cafe") } failed to parse '0xcafe' as hex because it contains the '0x' prefix ContainsPrefixError { hex: InputString("0xcafe") } --- units/src/parse.rs | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/units/src/parse.rs b/units/src/parse.rs index 52ea0e74b..9e670c5bb 100644 --- a/units/src/parse.rs +++ b/units/src/parse.rs @@ -2,7 +2,6 @@ //! Parsing utilities. -use alloc::string::String; use core::fmt; use core::str::FromStr; @@ -167,7 +166,7 @@ pub fn hex_remove_prefix(s: &str) -> Result<&str, PrefixedHexError> { } else if let Some(checked) = s.strip_prefix("0X") { Ok(checked) } else { - Err(MissingPrefixError::new(s.into()).into()) + Err(MissingPrefixError::new(s).into()) } } @@ -178,7 +177,7 @@ pub fn hex_remove_prefix(s: &str) -> Result<&str, PrefixedHexError> { /// If the input string contains a prefix. pub fn hex_check_unprefixed(s: &str) -> Result<&str, UnprefixedHexError> { if s.starts_with("0x") || s.starts_with("0X") { - return Err(ContainsPrefixError::new(s.into()).into()); + return Err(ContainsPrefixError::new(s).into()); } Ok(s) } @@ -375,17 +374,17 @@ impl From for UnprefixedHexError { /// Error returned when a hex string is missing a prefix (e.g. `0x`). #[derive(Debug, Clone, Eq, PartialEq)] pub struct MissingPrefixError { - hex: String, + hex: InputString, } impl MissingPrefixError { /// Creates an error from the string with the missing prefix. - pub(crate) fn new(hex: String) -> Self { Self { hex } } + pub(crate) fn new(hex: &str) -> Self { Self { hex: hex.into() } } } impl fmt::Display for MissingPrefixError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "hex string is missing a prefix (e.g. 0x): {}", self.hex) + write!(f, "{} because it is missing the '0x' prefix", self.hex.display_cannot_parse("hex")) } } @@ -395,17 +394,17 @@ impl std::error::Error for MissingPrefixError {} /// Error when hex string contains a prefix (e.g. 0x). #[derive(Debug, Clone, Eq, PartialEq)] pub struct ContainsPrefixError { - hex: String, + hex: InputString, } impl ContainsPrefixError { /// Creates an error from the string that contains the prefix. - pub(crate) fn new(hex: String) -> Self { Self { hex } } + pub(crate) fn new(hex: &str) -> Self { Self { hex: hex.into() } } } impl fmt::Display for ContainsPrefixError { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "hex string contains a prefix: {}", self.hex) + write!(f, "{} because it contains the '0x' prefix", self.hex.display_cannot_parse("hex")) } } From 38b8c6f5ea2d997e08aae496ed333abeedab9406 Mon Sep 17 00:00:00 2001 From: "Tobin C. Harding" Date: Fri, 1 Nov 2024 18:07:35 +1100 Subject: [PATCH 4/4] units: Remove a bunch of feature gateing Remove `alloc` feature gating from all modules in `units`! --- units/src/lib.rs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/units/src/lib.rs b/units/src/lib.rs index 189e11aff..f0e3994a1 100644 --- a/units/src/lib.rs +++ b/units/src/lib.rs @@ -22,23 +22,16 @@ extern crate alloc; extern crate std; pub mod amount; -#[cfg(feature = "alloc")] pub mod block; -#[cfg(feature = "alloc")] pub mod fee_rate; -#[cfg(feature = "alloc")] pub mod locktime; -#[cfg(feature = "alloc")] pub mod parse; -#[cfg(feature = "alloc")] pub mod weight; -#[doc(inline)] -pub use self::amount::{Amount, SignedAmount}; -#[cfg(feature = "alloc")] #[doc(inline)] #[rustfmt::skip] pub use self::{ + amount::{Amount, SignedAmount}, block::{BlockHeight, BlockInterval}, fee_rate::FeeRate, weight::Weight