Flesh out hex unit parsing API
Add to `units::parse` the complete suit of hex unit parsing functions: - remove prefix - assert without prefix - parse with or without prefix - parse with prefix - parse without prefix - parse prefix unchecked Refactor `bitcoin` to use the exact function we need, removing code duplication. This is a breaking change to `units`, it does however keep the current re-exports from the public, now empty, `bitcoin::error` module.
This commit is contained in:
parent
1142d16192
commit
a5b93cb159
|
@ -11,12 +11,11 @@ use core::fmt;
|
||||||
use io::{BufRead, Write};
|
use io::{BufRead, Write};
|
||||||
#[cfg(all(test, mutate))]
|
#[cfg(all(test, mutate))]
|
||||||
use mutagen::mutate;
|
use mutagen::mutate;
|
||||||
use units::parse;
|
use units::parse::{self, PrefixedHexError, UnprefixedHexError};
|
||||||
|
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
use crate::absolute;
|
use crate::absolute;
|
||||||
use crate::consensus::encode::{self, Decodable, Encodable};
|
use crate::consensus::encode::{self, Decodable, Encodable};
|
||||||
use crate::error::{ContainsPrefixError, MissingPrefixError, PrefixedHexError, UnprefixedHexError};
|
|
||||||
|
|
||||||
#[rustfmt::skip] // Keep public re-exports separate.
|
#[rustfmt::skip] // Keep public re-exports separate.
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
|
@ -92,26 +91,15 @@ impl LockTime {
|
||||||
/// The number of bytes that the locktime contributes to the size of a transaction.
|
/// The number of bytes that the locktime contributes to the size of a transaction.
|
||||||
pub const SIZE: usize = 4; // Serialized length of a u32.
|
pub const SIZE: usize = 4; // Serialized length of a u32.
|
||||||
|
|
||||||
/// Creates a `LockTime` from an prefixed hex string.
|
/// Creates a `LockTime` from a prefixed hex string.
|
||||||
pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
|
pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
|
||||||
let stripped = if let Some(stripped) = s.strip_prefix("0x") {
|
let lock_time = parse::hex_u32_prefixed(s)?;
|
||||||
stripped
|
|
||||||
} else if let Some(stripped) = s.strip_prefix("0X") {
|
|
||||||
stripped
|
|
||||||
} else {
|
|
||||||
return Err(MissingPrefixError::new(s).into());
|
|
||||||
};
|
|
||||||
|
|
||||||
let lock_time = parse::hex_u32(stripped)?;
|
|
||||||
Ok(Self::from_consensus(lock_time))
|
Ok(Self::from_consensus(lock_time))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `LockTime` from an unprefixed hex string.
|
/// Creates a `LockTime` from an unprefixed hex string.
|
||||||
pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
|
pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
|
||||||
if s.starts_with("0x") || s.starts_with("0X") {
|
let lock_time = parse::hex_u32_unprefixed(s)?;
|
||||||
return Err(ContainsPrefixError::new(s).into());
|
|
||||||
}
|
|
||||||
let lock_time = parse::hex_u32(s)?;
|
|
||||||
Ok(Self::from_consensus(lock_time))
|
Ok(Self::from_consensus(lock_time))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,7 +15,7 @@ use core::{cmp, fmt, str};
|
||||||
use hashes::{sha256d, Hash};
|
use hashes::{sha256d, Hash};
|
||||||
use internals::write_err;
|
use internals::write_err;
|
||||||
use io::{BufRead, Write};
|
use io::{BufRead, Write};
|
||||||
use units::parse;
|
use units::parse::{self, PrefixedHexError, UnprefixedHexError};
|
||||||
|
|
||||||
use super::Weight;
|
use super::Weight;
|
||||||
use crate::blockdata::locktime::absolute::{self, Height, Time};
|
use crate::blockdata::locktime::absolute::{self, Height, Time};
|
||||||
|
@ -24,7 +24,6 @@ use crate::blockdata::script::{Script, ScriptBuf};
|
||||||
use crate::blockdata::witness::Witness;
|
use crate::blockdata::witness::Witness;
|
||||||
use crate::blockdata::FeeRate;
|
use crate::blockdata::FeeRate;
|
||||||
use crate::consensus::{encode, Decodable, Encodable};
|
use crate::consensus::{encode, Decodable, Encodable};
|
||||||
use crate::error::{ContainsPrefixError, MissingPrefixError, PrefixedHexError, UnprefixedHexError};
|
|
||||||
use crate::internal_macros::{impl_consensus_encoding, impl_hashencode};
|
use crate::internal_macros::{impl_consensus_encoding, impl_hashencode};
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
#[cfg(doc)]
|
#[cfg(doc)]
|
||||||
|
@ -404,26 +403,15 @@ impl Sequence {
|
||||||
self.is_relative_lock_time() & (self.0 & Sequence::LOCK_TYPE_MASK > 0)
|
self.is_relative_lock_time() & (self.0 & Sequence::LOCK_TYPE_MASK > 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `Sequence` from an prefixed hex string.
|
/// Creates a `Sequence` from a prefixed hex string.
|
||||||
pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
|
pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
|
||||||
let stripped = if let Some(stripped) = s.strip_prefix("0x") {
|
let lock_time = parse::hex_u32_prefixed(s)?;
|
||||||
stripped
|
Ok(Self::from_consensus(lock_time))
|
||||||
} else if let Some(stripped) = s.strip_prefix("0X") {
|
|
||||||
stripped
|
|
||||||
} else {
|
|
||||||
return Err(MissingPrefixError::new(s).into());
|
|
||||||
};
|
|
||||||
|
|
||||||
let sequence = parse::hex_u32(stripped)?;
|
|
||||||
Ok(Self::from_consensus(sequence))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `Sequence` from an unprefixed hex string.
|
/// Creates a `Sequence` from an unprefixed hex string.
|
||||||
pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
|
pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
|
||||||
if s.starts_with("0x") || s.starts_with("0X") {
|
let lock_time = parse::hex_u32_unprefixed(s)?;
|
||||||
return Err(ContainsPrefixError::new(s).into());
|
|
||||||
}
|
|
||||||
let lock_time = parse::hex_u32(s)?;
|
|
||||||
Ok(Self::from_consensus(lock_time))
|
Ok(Self::from_consensus(lock_time))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,131 +2,8 @@
|
||||||
|
|
||||||
//! Contains error types and other error handling tools.
|
//! Contains error types and other error handling tools.
|
||||||
|
|
||||||
use core::fmt;
|
|
||||||
|
|
||||||
use internals::write_err;
|
|
||||||
|
|
||||||
use crate::prelude::*;
|
|
||||||
|
|
||||||
#[rustfmt::skip] // Keep public re-exports separate.
|
#[rustfmt::skip] // Keep public re-exports separate.
|
||||||
#[doc(inline)]
|
#[doc(inline)]
|
||||||
pub use crate::parse::ParseIntError;
|
pub use units::parse::{
|
||||||
|
ContainsPrefixError, MissingPrefixError, ParseIntError, PrefixedHexError, UnprefixedHexError,
|
||||||
/// Error returned when parsing integer from an supposedly prefixed hex string for
|
};
|
||||||
/// a type that can be created infallibly from an integer.
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub enum PrefixedHexError {
|
|
||||||
/// Hex string is missing prefix.
|
|
||||||
MissingPrefix(MissingPrefixError),
|
|
||||||
/// Error parsing integer from hex string.
|
|
||||||
ParseInt(ParseIntError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for PrefixedHexError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
use PrefixedHexError::*;
|
|
||||||
|
|
||||||
match *self {
|
|
||||||
MissingPrefix(ref e) => write_err!(f, "hex string is missing prefix"; e),
|
|
||||||
ParseInt(ref e) => write_err!(f, "prefixed hex string invalid int"; e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl std::error::Error for PrefixedHexError {
|
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
||||||
use PrefixedHexError::*;
|
|
||||||
|
|
||||||
match *self {
|
|
||||||
MissingPrefix(ref e) => Some(e),
|
|
||||||
ParseInt(ref e) => Some(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<MissingPrefixError> for PrefixedHexError {
|
|
||||||
fn from(e: MissingPrefixError) -> Self { Self::MissingPrefix(e) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ParseIntError> for PrefixedHexError {
|
|
||||||
fn from(e: ParseIntError) -> Self { Self::ParseInt(e) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Error returned when parsing integer from an supposedly un-prefixed hex string.
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub enum UnprefixedHexError {
|
|
||||||
/// Hex string contains prefix.
|
|
||||||
ContainsPrefix(ContainsPrefixError),
|
|
||||||
/// Error parsing integer from string.
|
|
||||||
ParseInt(ParseIntError),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for UnprefixedHexError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
use UnprefixedHexError::*;
|
|
||||||
|
|
||||||
match *self {
|
|
||||||
ContainsPrefix(ref e) => write_err!(f, "hex string is contains prefix"; e),
|
|
||||||
ParseInt(ref e) => write_err!(f, "hex string parse int"; e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl std::error::Error for UnprefixedHexError {
|
|
||||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
|
||||||
use UnprefixedHexError::*;
|
|
||||||
|
|
||||||
match *self {
|
|
||||||
ContainsPrefix(ref e) => Some(e),
|
|
||||||
ParseInt(ref e) => Some(e),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ContainsPrefixError> for UnprefixedHexError {
|
|
||||||
fn from(e: ContainsPrefixError) -> Self { Self::ContainsPrefix(e) }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<ParseIntError> for UnprefixedHexError {
|
|
||||||
fn from(e: ParseIntError) -> Self { Self::ParseInt(e) }
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Error when hex string is missing a prefix (e.g. 0x).
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
|
||||||
pub struct MissingPrefixError {
|
|
||||||
hex: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MissingPrefixError {
|
|
||||||
pub(crate) fn new(s: &str) -> Self { Self { hex: s.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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl ContainsPrefixError {
|
|
||||||
pub(crate) fn new(s: &str) -> Self { Self { hex: s.into() } }
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ContainsPrefixError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
write!(f, "hex string contains a prefix: {}", self.hex)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
impl std::error::Error for ContainsPrefixError {}
|
|
||||||
|
|
|
@ -18,9 +18,7 @@ use crate::block::Header;
|
||||||
use crate::blockdata::block::BlockHash;
|
use crate::blockdata::block::BlockHash;
|
||||||
use crate::consensus::encode::{self, Decodable, Encodable};
|
use crate::consensus::encode::{self, Decodable, Encodable};
|
||||||
use crate::consensus::Params;
|
use crate::consensus::Params;
|
||||||
use crate::error::{
|
use crate::error::{ParseIntError, PrefixedHexError, UnprefixedHexError};
|
||||||
ContainsPrefixError, MissingPrefixError, ParseIntError, PrefixedHexError, UnprefixedHexError,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Implement traits and methods shared by `Target` and `Work`.
|
/// Implement traits and methods shared by `Target` and `Work`.
|
||||||
macro_rules! do_impl {
|
macro_rules! do_impl {
|
||||||
|
@ -350,27 +348,16 @@ do_impl!(Target);
|
||||||
pub struct CompactTarget(u32);
|
pub struct CompactTarget(u32);
|
||||||
|
|
||||||
impl CompactTarget {
|
impl CompactTarget {
|
||||||
/// Creates a `CompactTarget` from an prefixed hex string.
|
/// Creates a `CompactTarget` from a prefixed hex string.
|
||||||
pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
|
pub fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
|
||||||
let stripped = if let Some(stripped) = s.strip_prefix("0x") {
|
let target = parse::hex_u32_prefixed(s)?;
|
||||||
stripped
|
|
||||||
} else if let Some(stripped) = s.strip_prefix("0X") {
|
|
||||||
stripped
|
|
||||||
} else {
|
|
||||||
return Err(MissingPrefixError::new(s).into());
|
|
||||||
};
|
|
||||||
|
|
||||||
let target = parse::hex_u32(stripped)?;
|
|
||||||
Ok(Self::from_consensus(target))
|
Ok(Self::from_consensus(target))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a `CompactTarget` from an unprefixed hex string.
|
/// Creates a `CompactTarget` from an unprefixed hex string.
|
||||||
pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
|
pub fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
|
||||||
if s.starts_with("0x") || s.starts_with("0X") {
|
let target = parse::hex_u32_unprefixed(s)?;
|
||||||
return Err(ContainsPrefixError::new(s).into());
|
Ok(Self::from_consensus(target))
|
||||||
}
|
|
||||||
let lock_time = parse::hex_u32(s)?;
|
|
||||||
Ok(Self::from_consensus(lock_time))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Computes the [`CompactTarget`] from a difficulty adjustment.
|
/// Computes the [`CompactTarget`] from a difficulty adjustment.
|
||||||
|
@ -499,36 +486,28 @@ impl U256 {
|
||||||
|
|
||||||
/// Creates a `U256` from a prefixed hex string.
|
/// Creates a `U256` from a prefixed hex string.
|
||||||
fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
|
fn from_hex(s: &str) -> Result<Self, PrefixedHexError> {
|
||||||
let stripped = if let Some(stripped) = s.strip_prefix("0x") {
|
let checked = parse::hex_remove_prefix(s)?;
|
||||||
stripped
|
Ok(U256::from_hex_internal(checked)?)
|
||||||
} 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 `U256` from an unprefixed hex string.
|
/// Creates a `U256` from an unprefixed hex string.
|
||||||
fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
|
fn from_unprefixed_hex(s: &str) -> Result<Self, UnprefixedHexError> {
|
||||||
if s.starts_with("0x") || s.starts_with("0X") {
|
let checked = parse::hex_check_unprefixed(s)?;
|
||||||
return Err(ContainsPrefixError::new(s).into());
|
Ok(U256::from_hex_internal(checked)?)
|
||||||
}
|
|
||||||
Ok(U256::from_hex_internal(s)?)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Caller to ensure `s` does not contain a prefix.
|
// Caller to ensure `s` does not contain a prefix.
|
||||||
fn from_hex_internal(s: &str) -> Result<Self, ParseIntError> {
|
fn from_hex_internal(s: &str) -> Result<Self, ParseIntError> {
|
||||||
let (high, low) = if s.len() < 32 {
|
let (high, low) = if s.len() < 32 {
|
||||||
let low = parse::hex_u128(s)?;
|
let low = parse::hex_u128_unchecked(s)?;
|
||||||
(0, low)
|
(0, low)
|
||||||
} else {
|
} else {
|
||||||
let high_len = s.len() - 32;
|
let high_len = s.len() - 32;
|
||||||
let high_s = &s[..high_len];
|
let high_s = &s[..high_len];
|
||||||
let low_s = &s[high_len..];
|
let low_s = &s[high_len..];
|
||||||
|
|
||||||
let high = parse::hex_u128(high_s)?;
|
let high = parse::hex_u128_unchecked(high_s)?;
|
||||||
let low = parse::hex_u128(low_s)?;
|
let low = parse::hex_u128_unchecked(low_s)?;
|
||||||
(high, low)
|
(high, low)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -6,7 +6,9 @@ use core::fmt;
|
||||||
|
|
||||||
use internals::write_err;
|
use internals::write_err;
|
||||||
|
|
||||||
use crate::parse::{self, ParseIntError};
|
use crate::parse::ParseIntError;
|
||||||
|
#[cfg(feature = "alloc")]
|
||||||
|
use crate::parse;
|
||||||
#[cfg(feature = "alloc")]
|
#[cfg(feature = "alloc")]
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
|
@ -233,7 +235,7 @@ where
|
||||||
S: AsRef<str> + Into<String>,
|
S: AsRef<str> + Into<String>,
|
||||||
F: FnOnce(u32) -> Result<T, ConversionError>,
|
F: FnOnce(u32) -> Result<T, ConversionError>,
|
||||||
{
|
{
|
||||||
let n = i64::from_str_radix(parse::strip_hex_prefix(s.as_ref()), 16)
|
let n = i64::from_str_radix(parse::hex_remove_optional_prefix(s.as_ref()), 16)
|
||||||
.map_err(ParseError::invalid_int(s))?;
|
.map_err(ParseError::invalid_int(s))?;
|
||||||
let n = u32::try_from(n).map_err(|_| ParseError::Conversion(n))?;
|
let n = u32::try_from(n).map_err(|_| ParseError::Conversion(n))?;
|
||||||
f(n).map_err(ParseError::from).map_err(Into::into)
|
f(n).map_err(ParseError::from).map_err(Into::into)
|
||||||
|
|
|
@ -88,43 +88,6 @@ 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") {
|
|
||||||
stripped
|
|
||||||
} else if let Some(stripped) = s.strip_prefix("0X") {
|
|
||||||
stripped
|
|
||||||
} else {
|
|
||||||
s
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Implements `TryFrom<$from> for $to` using `parse::int`, mapping the output using infallible
|
/// Implements `TryFrom<$from> for $to` using `parse::int`, mapping the output using infallible
|
||||||
/// conversion function `fn`.
|
/// conversion function `fn`.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
|
@ -197,6 +160,263 @@ macro_rules! impl_parse_str {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Removes the prefix `0x` (or `0X`) from hex string.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If input string does not contain a prefix.
|
||||||
|
pub fn hex_remove_prefix(s: &str) -> Result<&str, PrefixedHexError> {
|
||||||
|
if let Some(checked) = s.strip_prefix("0x") {
|
||||||
|
Ok(checked)
|
||||||
|
} else if let Some(checked) = s.strip_prefix("0X") {
|
||||||
|
Ok(checked)
|
||||||
|
} else {
|
||||||
|
Err(MissingPrefixError::new(s.into()).into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Checks hex string does not have a prefix `0x` (or `0X`).
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If 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());
|
||||||
|
}
|
||||||
|
Ok(s)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a `u32` from a hex string.
|
||||||
|
///
|
||||||
|
/// Input string may or may not contain a `0x` (or `0X`) prefix.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If the input string is not a valid hex encoding of a `u32`.
|
||||||
|
pub fn hex_u32(s: &str) -> Result<u32, ParseIntError> {
|
||||||
|
let unchecked = hex_remove_optional_prefix(s);
|
||||||
|
Ok(hex_u32_unchecked(unchecked)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a `u32` from a prefixed hex string.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// - If input string does not contain a `0x` (or `0X`) prefix.
|
||||||
|
/// - If input string is not a valid hex encoding of a `u32`.
|
||||||
|
pub fn hex_u32_prefixed(s: &str) -> Result<u32, PrefixedHexError> {
|
||||||
|
let checked = hex_remove_prefix(s)?;
|
||||||
|
Ok(hex_u32_unchecked(checked)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a `u32` from an unprefixed hex string.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// - If input string contains a `0x` (or `0X`) prefix.
|
||||||
|
/// - If input string is not a valid hex encoding of a `u32`.
|
||||||
|
pub fn hex_u32_unprefixed(s: &str) -> Result<u32, UnprefixedHexError> {
|
||||||
|
let checked = hex_check_unprefixed(s)?;
|
||||||
|
Ok(hex_u32_unchecked(checked)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a `u32` from a hex string.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// - If input string is not a valid hex encoding of a `u32`.
|
||||||
|
/// - With `InvalidDigit` due to the `x` if there is a prefix.
|
||||||
|
pub fn hex_u32_unchecked(s: &str) -> Result<u32, ParseIntError> {
|
||||||
|
u32::from_str_radix(s, 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` (or `0X`) prefix.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// If the input string is not a valid hex encoding of a `u128`.
|
||||||
|
pub fn hex_u128(s: &str) -> Result<u128, ParseIntError> {
|
||||||
|
let unchecked = hex_remove_optional_prefix(s);
|
||||||
|
Ok(hex_u128_unchecked(unchecked)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a `u128` from a hex string.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// - If input string does not contain a `0x` (or `0X`) prefix.
|
||||||
|
/// - If input string is not a valid hex encoding of a `u128`.
|
||||||
|
pub fn hex_u128_prefixed(s: &str) -> Result<u128, PrefixedHexError> {
|
||||||
|
let checked = hex_remove_prefix(s)?;
|
||||||
|
Ok(hex_u128_unchecked(checked)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a `u128` from a hex string.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// - If input string contains a `0x` (or `0X`) prefix.
|
||||||
|
/// - If input string is not a valid hex encoding of a `u128`.
|
||||||
|
pub fn hex_u128_unprefixed(s: &str) -> Result<u128, UnprefixedHexError> {
|
||||||
|
let checked = hex_check_unprefixed(s)?;
|
||||||
|
Ok(hex_u128_unchecked(checked)?)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses a `u128` from a hex string.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// - If input string is not a valid hex encoding of a `u128`.
|
||||||
|
/// - With `InvalidDigit` due to the `x` if there is a prefix.
|
||||||
|
pub fn hex_u128_unchecked(s: &str) -> Result<u128, ParseIntError> {
|
||||||
|
u128::from_str_radix(s, 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 hex_remove_optional_prefix(s: &str) -> &str {
|
||||||
|
if let Some(stripped) = s.strip_prefix("0x") {
|
||||||
|
stripped
|
||||||
|
} else if let Some(stripped) = s.strip_prefix("0X") {
|
||||||
|
stripped
|
||||||
|
} else {
|
||||||
|
s
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error returned when parsing integer from an supposedly prefixed hex string for
|
||||||
|
/// a type that can be created infallibly from an integer.
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub enum PrefixedHexError {
|
||||||
|
/// Hex string is missing prefix.
|
||||||
|
MissingPrefix(MissingPrefixError),
|
||||||
|
/// Error parsing integer from hex string.
|
||||||
|
ParseInt(ParseIntError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for PrefixedHexError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use PrefixedHexError::*;
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
MissingPrefix(ref e) => write_err!(f, "hex string is missing prefix"; e),
|
||||||
|
ParseInt(ref e) => write_err!(f, "prefixed hex string invalid int"; e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for PrefixedHexError {
|
||||||
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
use PrefixedHexError::*;
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
MissingPrefix(ref e) => Some(e),
|
||||||
|
ParseInt(ref e) => Some(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<MissingPrefixError> for PrefixedHexError {
|
||||||
|
fn from(e: MissingPrefixError) -> Self { Self::MissingPrefix(e) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParseIntError> for PrefixedHexError {
|
||||||
|
fn from(e: ParseIntError) -> Self { Self::ParseInt(e) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error returned when parsing integer from an supposedly un-prefixed hex string.
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub enum UnprefixedHexError {
|
||||||
|
/// Hex string contains prefix.
|
||||||
|
ContainsPrefix(ContainsPrefixError),
|
||||||
|
/// Error parsing integer from string.
|
||||||
|
ParseInt(ParseIntError),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for UnprefixedHexError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
use UnprefixedHexError::*;
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
ContainsPrefix(ref e) => write_err!(f, "hex string is contains prefix"; e),
|
||||||
|
ParseInt(ref e) => write_err!(f, "hex string parse int"; e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for UnprefixedHexError {
|
||||||
|
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||||
|
use UnprefixedHexError::*;
|
||||||
|
|
||||||
|
match *self {
|
||||||
|
ContainsPrefix(ref e) => Some(e),
|
||||||
|
ParseInt(ref e) => Some(e),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ContainsPrefixError> for UnprefixedHexError {
|
||||||
|
fn from(e: ContainsPrefixError) -> Self { Self::ContainsPrefix(e) }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<ParseIntError> for UnprefixedHexError {
|
||||||
|
fn from(e: ParseIntError) -> Self { Self::ParseInt(e) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Error when hex string is missing a prefix (e.g. 0x).
|
||||||
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
|
pub struct MissingPrefixError {
|
||||||
|
hex: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MissingPrefixError {
|
||||||
|
/// Creates an error from the string with the missing prefix.
|
||||||
|
pub(crate) fn new(hex: String) -> Self { Self { hex } }
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
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,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ContainsPrefixError {
|
||||||
|
/// Creates an error from the string that contains the prefix.
|
||||||
|
pub(crate) fn new(hex: String) -> Self { Self { hex } }
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for ContainsPrefixError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||||
|
write!(f, "hex string contains a prefix: {}", self.hex)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
impl std::error::Error for ContainsPrefixError {}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
@ -228,4 +448,9 @@ mod tests {
|
||||||
let got = hex_u128("deadbeef").expect("failed to parse non-prefixed hex");
|
let got = hex_u128("deadbeef").expect("failed to parse non-prefixed hex");
|
||||||
assert_eq!(got, want);
|
assert_eq!(got, want);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn parse_u32_from_hex_unchecked_errors_on_prefix() {
|
||||||
|
assert!(hex_u32_unchecked("0xab").is_err());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue