pub(super) fn parse_ascii_int<T: ParseAsciiInt>(bytes: &[u8]) -> Option<T> {
T::parse_ascii_int(bytes)
}
pub(super) trait ParseAsciiInt: Sized + private::Sealed {
fn parse_ascii_int(bytes: &[u8]) -> Option<Self>;
}
mod private {
pub trait Sealed {}
}
macro_rules! impl_unsigned {
($($Unsigned:ident),+) => {
$(
impl private::Sealed for $Unsigned {}
impl ParseAsciiInt for $Unsigned {
fn parse_ascii_int(bytes: &[u8]) -> Option<Self> {
if bytes.is_empty() {
return None;
}
let (negative, rest) = match bytes[0] {
b'+' => (false, &bytes[1..]),
b'-' => (true, &bytes[1..]),
_ => (false, bytes),
};
if rest.is_empty() {
return None;
}
let mut n: $Unsigned = 0;
for &b in rest {
let d = b.wrapping_sub(b'0');
if d > 9 {
return None;
}
n = n.checked_mul(10)?.checked_add(d as $Unsigned)?;
}
if negative && n != 0 {
return None;
}
Some(n)
}
}
)+
};
}
macro_rules! impl_signed {
($($Signed:ident),+) => {
$(
impl private::Sealed for $Signed {}
impl ParseAsciiInt for $Signed {
fn parse_ascii_int(bytes: &[u8]) -> Option<Self> {
if bytes.is_empty() {
return None;
}
let (negative, rest) = match bytes[0] {
b'+' => (false, &bytes[1..]),
b'-' => (true, &bytes[1..]),
_ => (false, bytes),
};
if rest.is_empty() {
return None;
}
let mut n: $Signed = 0;
if negative {
for &b in rest {
let d = b.wrapping_sub(b'0');
if d > 9 {
return None;
}
n = n.checked_mul(10)?.checked_sub(d as $Signed)?;
}
} else {
for &b in rest {
let d = b.wrapping_sub(b'0');
if d > 9 {
return None;
}
n = n.checked_mul(10)?.checked_add(d as $Signed)?;
}
}
Some(n)
}
}
)+
};
}
impl_unsigned!(u8, u16, u32, u64);
impl_signed!(i8, i16, i32, i64);