use crate::error::write_err;
use crate::error::impl_std_error;
use std::fmt;
use std::str::FromStr;
use std::convert::TryFrom;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ParseIntError {
input: String,
bits: u8,
is_signed: bool,
source: std::num::ParseIntError,
}
impl ParseIntError {
pub fn input(&self) -> &str {
&self.input
}
}
impl From<ParseIntError> for std::num::ParseIntError {
fn from(value: ParseIntError) -> Self {
value.source
}
}
impl AsRef<std::num::ParseIntError> for ParseIntError {
fn as_ref(&self) -> &std::num::ParseIntError {
&self.source
}
}
impl fmt::Display for ParseIntError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let signed = if self.is_signed { "signed" } else { "unsigned" };
let n = if self.bits == 8 { "n" } else { "" };
write_err!(f, "failed to parse '{}' as a{} {}-bit {} integer", self.input, n, self.bits, signed; self.source)
}
}
pub(crate) trait Integer: FromStr<Err=std::num::ParseIntError> + TryFrom<i8> + Sized {}
macro_rules! impl_integer {
($($type:ty),* $(,)?) => {
$(
impl Integer for $type {}
)*
}
}
impl_integer!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128);
pub(crate) fn int<T: Integer, S: AsRef<str> + Into<String>>(s: S) -> Result<T, ParseIntError> {
s.as_ref().parse().map_err(|error| {
ParseIntError {
input: s.into(),
bits: u8::try_from(std::mem::size_of::<T>() * 8).expect("max is 128 bits for u128"),
is_signed: T::try_from(-1i8).is_ok(),
source: error,
}
})
}
impl_std_error!(ParseIntError, source);
macro_rules! impl_tryfrom_str_through_int_single {
($($from:ty, $to:ident $(, $fn:ident)?);*) => {
$(
impl std::convert::TryFrom<$from> for $to {
type Error = $crate::error::ParseIntError;
fn try_from(s: $from) -> Result<Self, Self::Error> {
$crate::parse::int(s).map($to $(:: $fn)?)
}
}
)*
}
}
pub(crate) use impl_tryfrom_str_through_int_single;
macro_rules! impl_parse_str_through_int {
($to:ident $(, $fn:ident)?) => {
$crate::parse::impl_tryfrom_str_through_int_single!(&str, $to $(, $fn)?; String, $to $(, $fn)?; Box<str>, $to $(, $fn)?);
impl std::str::FromStr for $to {
type Err = $crate::error::ParseIntError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
$crate::parse::int(s).map($to $(:: $fn)?)
}
}
}
}
pub(crate) use impl_parse_str_through_int;