use crate::{Integer, Uint};
use core::num::IntErrorKind;
#[doc(hidden)]
#[derive(Debug)]
pub enum ParseIntLiteralError {
OutOfRange,
NoDigits,
InvalidDigit,
UnsignedNegation,
}
#[doc(hidden)]
pub struct IntLiteralParser<const IMPLICIT: bool, const S: bool, const N: usize, const B: usize, const OM: u8>;
impl<const S: bool, const N: usize, const B: usize, const OM: u8> IntLiteralParser<true, S, N, B, OM> {
#[doc(hidden)]
#[inline]
pub const fn parse<const R: bool, const M: usize, const A: usize, const OM1: u8>(negative: bool, radix: u32, literal_str_bytes: &[u8]) -> Integer<R, M, A, OM1> {
Integer::from_literal_str(negative, radix, literal_str_bytes)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> IntLiteralParser<false, S, N, B, OM> {
#[doc(hidden)]
#[inline]
pub const fn parse(negative: bool, radix: u32, literal_str_bytes: &[u8]) -> Integer<S, N, B, OM> {
Integer::from_literal_str(negative, radix, literal_str_bytes)
}
}
impl<const S: bool, const N: usize, const B: usize, const OM: u8> Integer<S, N, B, OM> {
#[doc(hidden)]
#[inline]
pub const fn from_literal_str(negative: bool, radix: u32, digit_bytes: &[u8]) -> Self {
match Self::from_literal_str_checked(negative, radix, digit_bytes) {
Ok(n) => n,
Err(err) => match err {
ParseIntLiteralError::OutOfRange => {
panic!("literal out of range for target type")
}
ParseIntLiteralError::NoDigits => {
panic!("no valid digits found for number")
}
ParseIntLiteralError::InvalidDigit => {
panic!("integer literal contains invalid digit")
}
ParseIntLiteralError::UnsignedNegation => {
panic!("cannot apply unary operator `-` to unsigned integer type")
}
},
}
}
#[doc(hidden)]
#[inline]
pub const fn from_literal_str_checked(negative: bool, radix: u32, digit_bytes: &[u8]) -> Result<Self, ParseIntLiteralError> {
if digit_bytes.is_empty() {
return Err(ParseIntLiteralError::NoDigits);
}
if negative && !S {
return Err(ParseIntLiteralError::UnsignedNegation);
}
match Uint::from_buf_radix::<true, true, true>(digit_bytes, radix) {
Ok(uint) => {
let out = uint.force_sign::<S>();
if S && negative {
if uint.gt(&Self::MIN.force_sign()) {
Err(ParseIntLiteralError::OutOfRange)
} else {
Ok(out.wrapping_neg()) }
} else {
if out.is_negative_internal() {
Err(ParseIntLiteralError::OutOfRange)
} else {
Ok(out)
}
}
}
Err(err) => match err.kind() {
IntErrorKind::Empty => Err(ParseIntLiteralError::NoDigits),
IntErrorKind::InvalidDigit => Err(ParseIntLiteralError::InvalidDigit),
IntErrorKind::PosOverflow | IntErrorKind::NegOverflow => {
Err(ParseIntLiteralError::OutOfRange)
}
_ => unreachable!(),
},
}
}
}