use core::str::FromStr;
#[rustfmt::skip] #[doc(no_inline)]
pub use self::error::{ParseIntError, PrefixedHexError, UnprefixedHexError};
pub trait Integer:
FromStr<Err = core::num::ParseIntError> + TryFrom<i8> + Sized + sealed::Sealed
{
}
macro_rules! impl_integer {
($($type:ty),* $(,)?) => {
$(
impl Integer for $type {}
impl sealed::Sealed for $type {}
)*
}
}
impl_integer!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128);
mod sealed {
pub trait Sealed {}
}
#[inline]
pub fn int_from_str<T: Integer>(s: &str) -> Result<T, ParseIntError> { int(s) }
#[inline]
#[cfg(feature = "alloc")]
pub fn int_from_string<T: Integer>(s: alloc::string::String) -> Result<T, ParseIntError> { int(s) }
#[inline]
#[cfg(feature = "alloc")]
pub fn int_from_box<T: Integer>(s: alloc::boxed::Box<str>) -> Result<T, ParseIntError> { int(s) }
#[inline]
fn int<T: Integer, S: AsRef<str> + error::BoundedInput>(s: S) -> Result<T, ParseIntError> {
s.as_ref().parse().map_err(|error| {
let (input, truncated) = s.into_bounded_input();
ParseIntError {
input,
bits: u16::try_from(core::mem::size_of::<T>() * 8).expect("max is 128 bits for u128"),
is_signed: T::try_from(-1i8).is_ok(),
truncated,
source: error,
}
})
}
macro_rules! impl_parse_str_from_int_infallible {
($to:ident, $inner:ident, $fn:ident) => {
impl $crate::_export::_core::str::FromStr for $to {
type Err = $crate::parse_int::ParseIntError;
#[inline]
fn from_str(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Err> {
$crate::_export::_core::convert::TryFrom::try_from(s)
}
}
impl $crate::_export::_core::convert::TryFrom<&str> for $to {
type Error = $crate::parse_int::ParseIntError;
#[inline]
fn try_from(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Error> {
$crate::parse_int::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_int::ParseIntError;
#[inline]
fn try_from(
s: alloc::string::String,
) -> $crate::_export::_core::result::Result<Self, Self::Error> {
$crate::parse_int::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_int::ParseIntError;
#[inline]
fn try_from(
s: alloc::boxed::Box<str>,
) -> $crate::_export::_core::result::Result<Self, Self::Error> {
$crate::parse_int::int_from_box::<$inner>(s).map($to::$fn)
}
}
};
}
pub(crate) use impl_parse_str_from_int_infallible;
macro_rules! impl_parse_str {
($to:ty, $err:ty, $inner_fn:expr) => {
$crate::parse_int::impl_tryfrom_str!(&str, $to, $err, $inner_fn);
#[cfg(feature = "alloc")]
$crate::parse_int::impl_tryfrom_str!(alloc::string::String, $to, $err, $inner_fn; alloc::boxed::Box<str>, $to, $err, $inner_fn);
impl $crate::_export::_core::str::FromStr for $to {
type Err = $err;
#[inline]
fn from_str(s: &str) -> $crate::_export::_core::result::Result<Self, Self::Err> {
$inner_fn(s)
}
}
}
}
pub(crate) use impl_parse_str;
macro_rules! impl_tryfrom_str {
($($from:ty, $to:ty, $err:ty, $inner_fn:expr);*) => {
$(
impl $crate::_export::_core::convert::TryFrom<$from> for $to {
type Error = $err;
#[inline]
fn try_from(s: $from) -> $crate::_export::_core::result::Result<Self, Self::Error> {
$inner_fn(s)
}
}
)*
}
}
pub(crate) use impl_tryfrom_str;
#[inline]
pub(crate) 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(error::MissingPrefixError::new(s))
.map_err(error::PrefixedHexErrorInner::MissingPrefix)
.map_err(PrefixedHexError)
}
}
#[inline]
pub(crate) fn hex_check_unprefixed(s: &str) -> Result<&str, UnprefixedHexError> {
if s.starts_with("0x") || s.starts_with("0X") {
return Err(error::ContainsPrefixError::new(s))
.map_err(error::UnprefixedHexErrorInner::ContainsPrefix)
.map_err(UnprefixedHexError);
}
Ok(s)
}
macro_rules! parse_hex_for {
(
$int_type:ty, $bits:literal;
fn $any_hex_fn:ident();
fn $prefix_hex_fn:ident();
fn $unprefix_hex_fn:ident();
fn $uncheck_hex_fn:ident();
) => {
#[doc = "Parses a `"]
#[doc = stringify!($int_type)]
#[doc = "` from a hex string.\n\n"]
#[doc = "Input string may or may not contain a `0x` (or `0X`) prefix.\n\n"]
#[doc = "# Errors\n\nIf the input string is not a valid hex encoding of a `"]
#[doc = stringify!($int_type)]
#[doc = "`."]
#[inline]
pub fn $any_hex_fn(s: &str) -> Result<$int_type, ParseIntError> {
let unchecked = hex_remove_optional_prefix(s);
$uncheck_hex_fn(unchecked)
}
#[doc = "Parses a `"]
#[doc = stringify!($int_type)]
#[doc = "` from a prefixed hex string.\n\n"]
#[doc = "# Errors\n\n"]
#[doc = "- If the input string does not contain a `0x` (or `0X`) prefix.\n"]
#[doc = "- If the input string is not a valid hex encoding of a `"]
#[doc = stringify!($int_type)]
#[doc = "`."]
#[inline]
pub fn $prefix_hex_fn(s: &str) -> Result<$int_type, PrefixedHexError> {
let checked = hex_remove_prefix(s)?;
$uncheck_hex_fn(checked)
.map_err(error::PrefixedHexErrorInner::ParseInt)
.map_err(PrefixedHexError)
}
#[doc = "Parses a `"]
#[doc = stringify!($int_type)]
#[doc = "` from an unprefixed hex string.\n\n"]
#[doc = "# Errors\n\n"]
#[doc = "- If the input string contains a `0x` (or `0X`) prefix.\n"]
#[doc = "- If the input string is not a valid hex encoding of a `"]
#[doc = stringify!($int_type)]
#[doc = "`."]
#[inline]
pub fn $unprefix_hex_fn(s: &str) -> Result<$int_type, UnprefixedHexError> {
let checked = hex_check_unprefixed(s)?;
$uncheck_hex_fn(checked)
.map_err(error::UnprefixedHexErrorInner::ParseInt)
.map_err(UnprefixedHexError)
}
#[doc = "Parses a `"]
#[doc = stringify!($int_type)]
#[doc = "` from an unprefixed hex string without first checking for a prefix.\n\n"]
#[doc = "# Errors\n\n"]
#[doc = "- If the input string contains a `0x` (or `0X`) prefix,"]
#[doc = " returns `InvalidDigit` due to the `x`.\n"]
#[doc = "- If the input string is not a valid hex encoding of a `"]
#[doc = stringify!($int_type)]
#[doc = "`."]
#[inline]
fn $uncheck_hex_fn(s: &str) -> Result<$int_type, ParseIntError> {
<$int_type>::from_str_radix(s, 16).map_err(|error| {
let (input, truncated) = error::BoundedInput::into_bounded_input(s);
ParseIntError { input, bits: $bits, is_signed: false, truncated, source: error }
})
}
};
}
parse_hex_for!(
u16, 16;
fn hex_u16();
fn hex_u16_prefixed();
fn hex_u16_unprefixed();
fn hex_u16_unchecked();
);
parse_hex_for!(
u32, 32;
fn hex_u32();
fn hex_u32_prefixed();
fn hex_u32_unprefixed();
fn hex_u32_unchecked();
);
parse_hex_for!(
u64, 64;
fn hex_u64();
fn hex_u64_prefixed();
fn hex_u64_unprefixed();
fn hex_u64_unchecked();
);
parse_hex_for!(
u128, 128;
fn hex_u128();
fn hex_u128_prefixed();
fn hex_u128_unprefixed();
fn hex_u128_unchecked();
);
#[inline]
pub(crate) fn hex_u256_prefixed(s: &str) -> Result<internals::u256::U256, PrefixedHexError> {
let checked = hex_remove_prefix(s)?;
hex_u256_unchecked(checked)
.map_err(error::PrefixedHexErrorInner::ParseInt)
.map_err(PrefixedHexError)
}
#[inline]
pub(crate) fn hex_u256_unprefixed(s: &str) -> Result<internals::u256::U256, UnprefixedHexError> {
let checked = hex_check_unprefixed(s)?;
hex_u256_unchecked(checked)
.map_err(error::UnprefixedHexErrorInner::ParseInt)
.map_err(UnprefixedHexError)
}
pub(crate) fn hex_u256_unchecked(s: &str) -> Result<internals::u256::U256, ParseIntError> {
let digits = s.strip_prefix('+').unwrap_or(s);
if !s.is_ascii() || digits.contains('+') {
return u128::from_str_radix(s, 16)
.map_err(|error| {
let (input, truncated) = error::BoundedInput::into_bounded_input(s);
ParseIntError { input, bits: 256, is_signed: false, truncated, source: error }
})
.map(internals::u256::U256::from);
}
let (high, low) = if digits.len() <= 32 {
let low = hex_u128_unchecked(s)?;
(0, low)
} else {
let high_len = digits.len() - 32;
let high_s = &digits[..high_len];
let low_s = &digits[high_len..];
let high = hex_u128_unchecked(high_s)?;
let low = hex_u128_unchecked(low_s)?;
(high, low)
};
let mut bytes = [0u8; 32];
bytes[..16].copy_from_slice(&low.to_le_bytes());
bytes[16..].copy_from_slice(&high.to_le_bytes());
Ok(internals::u256::U256::from_le_bytes(bytes))
}
#[inline]
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
}
}
pub mod error {
use core::convert::Infallible;
use core::fmt;
use internals::error::InputString;
use internals::write_err;
pub(super) const ERROR_STRING_LEN_LIMIT: usize = 80;
pub(crate) trait BoundedInput: Into<InputString> {
fn into_bounded_input(self) -> (InputString, bool);
}
impl BoundedInput for &str {
fn into_bounded_input(self) -> (InputString, bool) {
if self.len() <= ERROR_STRING_LEN_LIMIT {
(self.into(), false)
} else {
let mut end = ERROR_STRING_LEN_LIMIT;
loop {
if let Some(truncated) = self.get(..end) {
break (truncated.into(), true);
}
end -= 1;
}
}
}
}
#[cfg(feature = "alloc")]
impl BoundedInput for alloc::string::String {
#[inline]
fn into_bounded_input(self) -> (InputString, bool) { (self.into(), false) }
}
#[cfg(feature = "alloc")]
impl BoundedInput for alloc::boxed::Box<str> {
#[inline]
fn into_bounded_input(self) -> (InputString, bool) { (self.into(), false) }
}
#[derive(Debug, Clone, PartialEq, Eq)]
#[non_exhaustive]
pub struct ParseIntError {
pub(crate) input: InputString,
pub(crate) bits: u16,
pub(crate) is_signed: bool,
pub(crate) truncated: bool,
pub(crate) source: core::num::ParseIntError,
}
impl From<Infallible> for ParseIntError {
#[inline]
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for ParseIntError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let signed = if self.is_signed { "signed" } else { "unsigned" };
let truncated = if self.truncated { "..." } else { "" };
write_err!(f, "{}{} ({}, {}-bit)", self.input.display_cannot_parse("integer"), truncated, signed, self.bits; self.source)
}
}
#[cfg(feature = "std")]
impl std::error::Error for ParseIntError {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { Some(&self.source) }
}
impl From<ParseIntError> for core::num::ParseIntError {
#[inline]
fn from(value: ParseIntError) -> Self { value.source }
}
impl AsRef<core::num::ParseIntError> for ParseIntError {
#[inline]
fn as_ref(&self) -> &core::num::ParseIntError { &self.source }
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct PrefixedHexError(pub(super) PrefixedHexErrorInner);
#[derive(Debug, Clone, Eq, PartialEq)]
pub(super) enum PrefixedHexErrorInner {
MissingPrefix(MissingPrefixError),
ParseInt(ParseIntError),
}
impl From<Infallible> for PrefixedHexError {
#[inline]
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for PrefixedHexError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use PrefixedHexErrorInner as E;
match self.0 {
E::MissingPrefix(ref e) => write_err!(f, "hex string is missing prefix"; e),
E::ParseInt(ref e) => write_err!(f, "prefixed hex string invalid int"; e),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for PrefixedHexError {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use PrefixedHexErrorInner as E;
match self.0 {
E::MissingPrefix(ref e) => Some(e),
E::ParseInt(ref e) => Some(e),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct UnprefixedHexError(pub(super) UnprefixedHexErrorInner);
#[derive(Debug, Clone, Eq, PartialEq)]
pub(super) enum UnprefixedHexErrorInner {
ContainsPrefix(ContainsPrefixError),
ParseInt(ParseIntError),
}
impl From<Infallible> for UnprefixedHexError {
#[inline]
fn from(never: Infallible) -> Self { match never {} }
}
impl fmt::Display for UnprefixedHexError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use UnprefixedHexErrorInner as E;
match self.0 {
E::ContainsPrefix(ref e) => write_err!(f, "hex string contains prefix"; e),
E::ParseInt(ref e) => write_err!(f, "hex string parse int"; e),
}
}
}
#[cfg(feature = "std")]
impl std::error::Error for UnprefixedHexError {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
use UnprefixedHexErrorInner as E;
match self.0 {
E::ContainsPrefix(ref e) => Some(e),
E::ParseInt(ref e) => Some(e),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub(super) struct MissingPrefixError {
hex: InputString,
truncated: bool,
}
impl MissingPrefixError {
#[inline]
pub(crate) fn new(hex: &str) -> Self {
let (hex, truncated) = hex.into_bounded_input();
Self { hex, truncated }
}
}
impl fmt::Display for MissingPrefixError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let truncated = if self.truncated { "..." } else { "" };
write!(
f,
"{}{} because it is missing the '0x' prefix",
self.hex.display_cannot_parse("hex"),
truncated
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for MissingPrefixError {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
let Self { hex: _, truncated: _ } = self;
None
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub(super) struct ContainsPrefixError {
hex: InputString,
truncated: bool,
}
impl ContainsPrefixError {
#[inline]
pub(crate) fn new(hex: &str) -> Self {
let (hex, truncated) = hex.into_bounded_input();
Self { hex, truncated }
}
}
impl fmt::Display for ContainsPrefixError {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let truncated = if self.truncated { "..." } else { "" };
write!(
f,
"{}{} because it contains the '0x' prefix",
self.hex.display_cannot_parse("hex"),
truncated
)
}
}
#[cfg(feature = "std")]
impl std::error::Error for ContainsPrefixError {
#[inline]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
let Self { hex: _, truncated: _ } = self;
None
}
}
}
#[cfg(test)]
mod tests {
#[cfg(feature = "alloc")]
use alloc::format;
#[cfg(feature = "alloc")]
use alloc::string::ToString;
#[cfg(feature = "std")]
use std::{error::Error, panic};
use super::*;
#[test]
fn parse_int() {
assert!(int_from_str::<u8>("1").is_ok());
let _ = int_from_str::<i8>("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]
#[cfg(feature = "alloc")]
fn parse_int_error_bounds_borrowed_input() {
let long = "f".repeat(error::ERROR_STRING_LEN_LIMIT + 100);
let err = int_from_str::<u32>(&long).unwrap_err();
assert!(err.truncated);
assert!(format!("{err}").contains("..."));
assert!(!format!("{err:?}").contains(&long));
let err = int_from_str::<u32>("nope").unwrap_err();
assert!(!err.truncated);
assert!(!format!("{err}").contains("..."));
}
#[test]
#[cfg(feature = "alloc")]
fn parse_int_error_retains_owned_input_in_full() {
let long = "f".repeat(error::ERROR_STRING_LEN_LIMIT + 100);
let err = int_from_string::<u32>(long.clone()).unwrap_err();
assert!(!err.truncated);
assert!(format!("{err:?}").contains(&long));
}
#[test]
#[cfg(feature = "std")]
fn parse_int_panic_when_populating_bits() {
#[allow(dead_code)]
struct TestTypeWithMoreThanU16Bits([u8; 8192]);
impl_integer!(TestTypeWithMoreThanU16Bits);
impl FromStr for TestTypeWithMoreThanU16Bits {
type Err = core::num::ParseIntError;
fn from_str(_: &str) -> Result<Self, Self::Err> {
"Always invalid for testing".parse::<u32>().map(|_| Self([0; 8192]))
}
}
impl From<i8> for TestTypeWithMoreThanU16Bits {
fn from(_: i8) -> Self { Self([0; 8192]) }
}
let result =
panic::catch_unwind(|| int_from_str::<TestTypeWithMoreThanU16Bits>("not a number"));
assert!(result.is_err());
}
#[test]
fn remove_prefix() {
let lower = "0xhello";
assert_eq!(hex_remove_prefix(lower).unwrap(), "hello");
let upper = "0Xhello";
assert_eq!(hex_remove_prefix(upper).unwrap(), "hello");
let err = "error";
assert!(hex_remove_prefix(err).is_err());
}
#[test]
fn check_unprefixed() {
let lower = "0xhello";
assert!(hex_check_unprefixed(lower).is_err());
let upper = "0Xhello";
assert!(hex_check_unprefixed(upper).is_err());
let valid = "hello";
assert_eq!(hex_check_unprefixed(valid).unwrap(), "hello");
}
#[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_prefixed_upper() {
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_hex_u32_prefixed() {
let want = 171; assert_eq!(hex_u32_prefixed("0xab").unwrap(), want);
assert!(hex_u32_unprefixed("0xab").is_err());
}
#[test]
fn parse_hex_u32_upper_prefixed() {
let want = 171; assert_eq!(hex_u32_prefixed("0Xab").unwrap(), want);
assert!(hex_u32_unprefixed("0Xab").is_err());
}
#[test]
fn parse_hex_u32_unprefixed() {
let want = 171; assert_eq!(hex_u32_unprefixed("ab").unwrap(), want);
assert!(hex_u32_prefixed("ab").is_err());
}
#[test]
fn parse_u128_from_hex_prefixed() {
let want = 3_735_928_559;
let got = hex_u128("0xdeadbeef").expect("failed to parse prefixed hex");
assert_eq!(got, want);
}
#[test]
fn parse_u128_from_hex_upper_prefixed() {
let want = 3_735_928_559;
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 = 3_735_928_559;
let got = hex_u128("deadbeef").expect("failed to parse non-prefixed hex");
assert_eq!(got, want);
}
#[test]
fn parse_hex_u128_prefixed() {
let want = 3_735_928_559;
assert_eq!(hex_u128_prefixed("0xdeadbeef").unwrap(), want);
assert!(hex_u128_unprefixed("0xdeadbeef").is_err());
}
#[test]
fn parse_hex_u128_upper_prefixed() {
let want = 3_735_928_559;
assert_eq!(hex_u128_prefixed("0Xdeadbeef").unwrap(), want);
assert!(hex_u128_unprefixed("0Xdeadbeef").is_err());
}
#[test]
fn parse_hex_u128_unprefixed() {
let want = 3_735_928_559;
assert_eq!(hex_u128_unprefixed("deadbeef").unwrap(), want);
assert!(hex_u128_prefixed("deadbeef").is_err());
}
#[test]
fn parse_u32_from_hex_unchecked_errors_on_prefix() {
assert!(hex_u32_unchecked("0xab").is_err());
assert!(hex_u32_unchecked("0Xab").is_err());
}
#[test]
fn parse_u32_from_hex_unchecked_errors_on_overflow() {
assert!(hex_u32_unchecked("1234abcd").is_ok());
assert!(hex_u32_unchecked("1234abcd1").is_err());
}
#[test]
fn parse_u128_from_hex_unchecked_errors_on_prefix() {
assert!(hex_u128_unchecked("0xdeadbeef").is_err());
assert!(hex_u128_unchecked("0Xdeadbeef").is_err());
}
#[test]
fn parse_u128_from_hex_unchecked_errors_on_overflow() {
assert!(hex_u128_unchecked("deadbeefabcdffffdeadbeefabcdffff").is_ok());
assert!(hex_u128_unchecked("deadbeefabcdffffdeadbeefabcdffff1").is_err());
}
#[test]
fn parse_u256_from_hex_non_ascii_reports_bit_length() {
let error = hex_u256_unchecked("é0000000000000000000000000000000").unwrap_err();
assert_eq!(error.bits, 256);
}
#[test]
#[cfg(feature = "alloc")]
fn missing_prefix_error_display_escapes_control_characters() {
let e = hex_u32_prefixed("bad\nlevel=INFO accepted=true").unwrap_err().to_string();
assert!(!e.chars().any(char::is_control));
}
#[test]
#[cfg(feature = "alloc")]
fn contains_prefix_error_display_escapes_control_characters() {
let e = hex_u32_unprefixed("0x1\nlevel=INFO accepted=true").unwrap_err().to_string();
assert!(!e.chars().any(char::is_control));
}
#[test]
#[cfg(feature = "alloc")]
fn error_display_is_non_empty() {
let e = int_from_str::<u32>("not_a_number").unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_some());
let e = hex_u32_prefixed("abc").unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_some());
let PrefixedHexError(error::PrefixedHexErrorInner::MissingPrefix(e)) = e else {
panic!("should be a MissingPrefixError")
};
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_none());
let e = hex_u32_prefixed("0xgabc").unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_some());
let e = hex_u32_unprefixed("0xabc").unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_some());
let UnprefixedHexError(error::UnprefixedHexErrorInner::ContainsPrefix(e)) = e else {
panic!("should be a ContainsPrefixError")
};
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_none());
let e = hex_u32_unprefixed("gabc").unwrap_err();
assert!(!e.to_string().is_empty());
#[cfg(feature = "std")]
assert!(e.source().is_some());
}
}