use core::fmt::{self, Display, Formatter};
#[cfg(feature = "std")]
use std::error::Error;
macro_rules! from_str_radix_impl {
($($ty:ident)*) => { $(
impl $crate::__private::Dispatch<$ty> {
pub const fn from_ascii_radix(src: &[u8], radix: u32) -> Result<$ty, ParseError> {
assert!(
2 <= radix && radix <= 36,
"from_str_radix: radix must lie in the range `[2, 36]`",
);
macro_rules! yeet {
($e:expr) => { return Err(ParseError { kind: $e }) };
}
let (positive, digits) = match *src {
[b'+', ref digits @ ..] => (true, digits),
[b'-', ref digits @ ..] => (false, digits),
ref digits => (true, digits),
};
if digits.is_empty() {
yeet!(ParseErrorKind::NoDigits);
}
let overflow_kind = if positive {
ParseErrorKind::AboveMax
} else {
ParseErrorKind::BelowMin
};
let mut result: $ty = 0;
let mut i = 0;
while i < digits.len() {
let digit = digits[i];
let Some(digit_value) = (digit as char).to_digit(radix) else {
yeet!(ParseErrorKind::InvalidDigit);
};
#[allow(clippy::cast_possible_wrap)]
#[allow(clippy::cast_possible_truncation)]
let Some(new_result) = result.checked_mul(radix as $ty) else {
yeet!(overflow_kind);
};
#[allow(clippy::cast_possible_wrap)]
#[allow(clippy::cast_possible_truncation)]
let Some(new_result) = (if positive {
new_result.checked_add(digit_value as $ty)
} else {
new_result.checked_sub(digit_value as $ty)
}) else {
yeet!(overflow_kind);
};
result = new_result;
i += 1;
}
Ok(result)
}
}
)* }
}
from_str_radix_impl! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize }
#[derive(Debug, Clone)]
pub struct ParseError {
kind: ParseErrorKind,
}
impl ParseError {
#[must_use]
pub fn kind(&self) -> ParseErrorKind {
self.kind
}
}
impl Display for ParseError {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self.kind() {
ParseErrorKind::NoDigits => f.write_str("no digits found"),
ParseErrorKind::InvalidDigit => f.write_str("invalid digit found in string"),
ParseErrorKind::AboveMax => f.write_str("number too high to fit in target range"),
ParseErrorKind::BelowMin => f.write_str("number too low to fit in target range"),
}
}
}
#[cfg(feature = "std")]
impl Error for ParseError {}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum ParseErrorKind {
#[non_exhaustive]
NoDigits,
#[non_exhaustive]
InvalidDigit,
#[non_exhaustive]
AboveMax,
#[non_exhaustive]
BelowMin,
}
#[must_use]
pub const fn error_below_min() -> ParseError {
ParseError {
kind: ParseErrorKind::BelowMin,
}
}
#[must_use]
pub const fn error_above_max() -> ParseError {
ParseError {
kind: ParseErrorKind::AboveMax,
}
}