use crate::number::{Integer, SignedInteger, UnsignedInteger};
use crate::parser::then::Then2;
use crate::parser::{ParseError, ParseResult, Parseable, Parser};
use std::marker::PhantomData;
use std::ops::RangeInclusive;
#[derive(Copy, Clone)]
pub struct UnsignedParser<U: UnsignedInteger>(PhantomData<U>);
impl<U: UnsignedInteger> Parser for UnsignedParser<U> {
type Output<'i> = U;
type Then<T: Parser> = Then2<Self, T>;
#[inline]
fn parse<'i>(&self, mut input: &'i [u8]) -> ParseResult<'i, Self::Output<'i>> {
let mut n = match input {
[d @ b'0'..=b'9', ..] => {
input = &input[1..];
U::from(d - b'0')
}
_ => return Err((ParseError::Expected("unsigned integer"), input)),
};
while let Some(d @ b'0'..=b'9') = input.first() {
n = n
.checked_mul(U::from(10))
.and_then(|n| n.checked_add(U::from(d - b'0')))
.ok_or((ParseError::too_large(U::MAX), input))?;
input = &input[1..];
}
Ok((n, input))
}
}
#[derive(Copy, Clone)]
pub struct SignedParser<S: SignedInteger>(PhantomData<S>);
impl<S: SignedInteger> Parser for SignedParser<S> {
type Output<'i> = S;
type Then<T: Parser> = Then2<Self, T>;
#[expect(clippy::cast_possible_wrap)]
#[inline]
fn parse<'i>(&self, mut input: &'i [u8]) -> ParseResult<'i, Self::Output<'i>> {
let (mut n, positive) = match input {
[d @ b'0'..=b'9', rem @ ..] | [b'+', d @ b'0'..=b'9', rem @ ..] => {
input = rem;
(S::from((d - b'0') as i8), true)
}
[b'-', d @ b'0'..=b'9', rem @ ..] => {
input = rem;
(S::from(-((d - b'0') as i8)), false)
}
_ => return Err((ParseError::Expected("signed integer"), input)),
};
if positive {
while let Some(d @ b'0'..=b'9') = input.first() {
n = n
.checked_mul(S::from(10))
.and_then(|n| n.checked_add(S::from((d - b'0') as i8)))
.ok_or((ParseError::too_large(S::MAX), input))?;
input = &input[1..];
}
} else {
while let Some(d @ b'0'..=b'9') = input.first() {
n = n
.checked_mul(S::from(10))
.and_then(|n| n.checked_sub(S::from((d - b'0') as i8)))
.ok_or((ParseError::too_small(S::MIN), input))?;
input = &input[1..];
}
}
Ok((n, input))
}
}
macro_rules! parser_for {
($p:ident => $($n:ident),+) => {$(
impl Parseable for std::primitive::$n {
type Parser = $p<std::primitive::$n>;
const PARSER: Self::Parser = $p(PhantomData);
}
#[doc = concat!("Parser for [`prim@", stringify!($n), "`] values.")]
#[must_use]
pub fn $n() -> $p<std::primitive::$n> {
$p(PhantomData)
}
)+};
}
parser_for! { UnsignedParser => u8, u16, u32, u64, u128 }
parser_for! { SignedParser => i8, i16, i32, i64, i128 }
#[derive(Copy, Clone)]
pub struct NumberRange<I> {
min: I,
max: I,
}
impl<I: Integer + Parseable> Parser for NumberRange<I> {
type Output<'i> = I;
type Then<T: Parser> = Then2<Self, T>;
fn parse<'i>(&self, input: &'i [u8]) -> ParseResult<'i, Self::Output<'i>> {
let (v, remaining) = I::PARSER.parse(input)?;
if v < self.min {
Err((ParseError::too_small(self.min), input))
} else if v > self.max {
Err((ParseError::too_large(self.max), input))
} else {
Ok((v, remaining))
}
}
}
#[inline]
#[must_use]
pub fn number_range<I: Integer + Parseable>(range: RangeInclusive<I>) -> NumberRange<I> {
let min = *range.start();
let max = *range.end();
assert!(min <= max);
NumberRange { min, max }
}