Merge rust-bitcoin/rust-bitcoin#2514: Add hex parsing to `pow` types
f019e24f1f
Add hex parsing to pow types (Tobin C. Harding)d33625f6e2
units: Introduce public hex_u128 function (Tobin C. Harding)9705d51782
docs: Use backticks on stdlib type (Tobin C. Harding)cf65bf035f
Introduce local variable (Tobin C. Harding)1269722770
Move helper function (Tobin C. Harding)dca054c680
test: Add unit tests for hex_u32 (Tobin C. Harding) Pull request description: The `pow` types implement `fmt::LowerHex` but do not implement hex parsing. Add inherent methods `from_hex` and `from_prefixed_hex` to the `pow` types - as we did for locktime types. ACKs for top commit: apoelstra: ACKf019e24f1f
sanket1729: ACKf019e24f1f
Tree-SHA512: d682e1259db1c2c0abe24a8ca137fc49abe0ed7ccce90de4d6058c7a4986d26c86a84289ec7377b9209648a57e0af6735c1eb3d39c9de6770fde1936f596dfd2
This commit is contained in:
commit
69716f17b9
|
@ -18,12 +18,22 @@ use units::parse;
|
|||
use crate::blockdata::block::BlockHash;
|
||||
use crate::consensus::encode::{self, Decodable, Encodable};
|
||||
use crate::consensus::Params;
|
||||
use crate::error::{ContainsPrefixError, MissingPrefixError, PrefixedHexError, UnprefixedHexError};
|
||||
use crate::error::{ContainsPrefixError, MissingPrefixError, ParseIntError, PrefixedHexError, UnprefixedHexError};
|
||||
|
||||
/// Implement traits and methods shared by `Target` and `Work`.
|
||||
macro_rules! do_impl {
|
||||
($ty:ident) => {
|
||||
impl $ty {
|
||||
/// Creates `Self` from a prefixed hex string.
|
||||
pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
|
||||
Ok($ty(U256::from_hex(s)?))
|
||||
}
|
||||
|
||||
/// Creates `Self` from an unprefixed hex string.
|
||||
pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
|
||||
Ok($ty(U256::from_unprefixed_hex(s)?))
|
||||
}
|
||||
|
||||
/// Creates `Self` from a big-endian byte array.
|
||||
#[inline]
|
||||
pub fn from_be_bytes(bytes: [u8; 32]) -> $ty { $ty(U256::from_be_bytes(bytes)) }
|
||||
|
@ -390,6 +400,43 @@ impl U256 {
|
|||
|
||||
const ONE: U256 = U256(0, 1);
|
||||
|
||||
/// Creates a `U256` from an prefixed hex string.
|
||||
fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
|
||||
let stripped = if let Some(stripped) = s.strip_prefix("0x") {
|
||||
stripped
|
||||
} else if let Some(stripped) = s.strip_prefix("0X") {
|
||||
stripped
|
||||
} else {
|
||||
return Err(MissingPrefixError::new(s).into());
|
||||
};
|
||||
Ok(U256::from_hex_internal(stripped)?)
|
||||
}
|
||||
|
||||
/// Creates a `CompactTarget` from an unprefixed hex string.
|
||||
fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
|
||||
if s.starts_with("0x") || s.starts_with("0X") {
|
||||
return Err(ContainsPrefixError::new(s).into());
|
||||
}
|
||||
Ok(U256::from_hex_internal(s)?)
|
||||
}
|
||||
|
||||
fn from_hex_internal(s: &str) -> Result<Self, ParseIntError> {
|
||||
let (high, low) = if s.len() < 32 {
|
||||
let low = parse::hex_u128(s)?;
|
||||
(0, low)
|
||||
} else {
|
||||
let high_len = s.len() - 32;
|
||||
let high_s = &s[..high_len];
|
||||
let low_s = &s[high_len..];
|
||||
|
||||
let high = parse::hex_u128(high_s)?;
|
||||
let low = parse::hex_u128(low_s)?;
|
||||
(high, low)
|
||||
};
|
||||
|
||||
Ok(U256(high, low))
|
||||
}
|
||||
|
||||
/// Creates [`U256`] from a big-endian array of `u8`s.
|
||||
#[cfg_attr(all(test, mutate), mutate)]
|
||||
fn from_be_bytes(a: [u8; 32]) -> U256 {
|
||||
|
@ -1507,6 +1554,28 @@ mod tests {
|
|||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn u256_to_from_hex_roundtrips() {
|
||||
let val = U256(
|
||||
0xDEAD_BEEA_A69B_455C_D41B_B662_A69B_4550,
|
||||
0xA69B_455C_D41B_B662_A69B_4555_DEAD_BEEF,
|
||||
);
|
||||
let hex = format!("0x{:x}", val);
|
||||
let got = U256::from_hex(&hex).expect("failed to parse hex");
|
||||
assert_eq!(got, val);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn u256_to_from_unprefixed_hex_roundtrips() {
|
||||
let val = U256(
|
||||
0xDEAD_BEEA_A69B_455C_D41B_B662_A69B_4550,
|
||||
0xA69B_455C_D41B_B662_A69B_4555_DEAD_BEEF,
|
||||
);
|
||||
let hex = format!("{:x}", val);
|
||||
let got = U256::from_unprefixed_hex(&hex).expect("failed to parse hex");
|
||||
assert_eq!(got, val);
|
||||
}
|
||||
|
||||
#[cfg(feature = "serde")]
|
||||
#[test]
|
||||
fn u256_serde() {
|
||||
|
|
|
@ -88,6 +88,32 @@ pub fn int<T: Integer, S: AsRef<str> + Into<String>>(s: S) -> Result<T, ParseInt
|
|||
})
|
||||
}
|
||||
|
||||
/// Parses a `u32` from a hex string.
|
||||
///
|
||||
/// Input string may or may not contain a `0x` prefix.
|
||||
pub fn hex_u32<S: AsRef<str> + Into<String>>(s: S) -> Result<u32, ParseIntError> {
|
||||
let stripped = strip_hex_prefix(s.as_ref());
|
||||
u32::from_str_radix(stripped, 16).map_err(|error| ParseIntError {
|
||||
input: s.into(),
|
||||
bits: 32,
|
||||
is_signed: false,
|
||||
source: error,
|
||||
})
|
||||
}
|
||||
|
||||
/// Parses a `u128` from a hex string.
|
||||
///
|
||||
/// Input string may or may not contain a `0x` prefix.
|
||||
pub fn hex_u128<S: AsRef<str> + Into<String>>(s: S) -> Result<u128, ParseIntError> {
|
||||
let stripped = strip_hex_prefix(s.as_ref());
|
||||
u128::from_str_radix(stripped, 16).map_err(|error| ParseIntError {
|
||||
input: s.into(),
|
||||
bits: 128,
|
||||
is_signed: false,
|
||||
source: error,
|
||||
})
|
||||
}
|
||||
|
||||
/// Strips the hex prefix off `s` if one is present.
|
||||
pub(crate) fn strip_hex_prefix(s: &str) -> &str {
|
||||
if let Some(stripped) = s.strip_prefix("0x") {
|
||||
|
@ -99,18 +125,6 @@ pub(crate) fn strip_hex_prefix(s: &str) -> &str {
|
|||
}
|
||||
}
|
||||
|
||||
/// Parses a u32 from a hex string.
|
||||
///
|
||||
/// Input string may or may not contain a `0x` prefix.
|
||||
pub fn hex_u32<S: AsRef<str> + Into<String>>(s: S) -> Result<u32, ParseIntError> {
|
||||
u32::from_str_radix(strip_hex_prefix(s.as_ref()), 16).map_err(|error| ParseIntError {
|
||||
input: s.into(),
|
||||
bits: 32,
|
||||
is_signed: false,
|
||||
source: error,
|
||||
})
|
||||
}
|
||||
|
||||
/// Implements `TryFrom<$from> for $to` using `parse::int`, mapping the output using infallible
|
||||
/// conversion function `fn`.
|
||||
#[macro_export]
|
||||
|
@ -182,3 +196,36 @@ macro_rules! impl_parse_str {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn parse_u32_from_hex_prefixed() {
|
||||
let want = 171;
|
||||
let got = hex_u32("0xab").expect("failed to parse prefixed hex");
|
||||
assert_eq!(got, want);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_u32_from_hex_no_prefix() {
|
||||
let want = 171;
|
||||
let got = hex_u32("ab").expect("failed to parse non-prefixed hex");
|
||||
assert_eq!(got, want);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_u128_from_hex_prefixed() {
|
||||
let want = 3735928559;
|
||||
let got = hex_u128("0xdeadbeef").expect("failed to parse prefixed hex");
|
||||
assert_eq!(got, want);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_u128_from_hex_no_prefix() {
|
||||
let want = 3735928559;
|
||||
let got = hex_u128("deadbeef").expect("failed to parse non-prefixed hex");
|
||||
assert_eq!(got, want);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue