use crate::dec2flt::dec2flt;
use super::error::{Error, ErrorKind, Expected};
use super::swar;
use super::syntax::Syntax;
use super::traits::{Float, Signed, Unsigned};
#[derive(Debug, Clone, Copy)]
pub(crate) enum Any {
Unsigned(u128),
Signed(i128),
Float(f64),
}
#[inline]
pub(crate) fn parse_unsigned_base<S, T>(input: &[u8]) -> Result<(T, usize), Error>
where
S: Syntax,
T: Unsigned,
{
unsigned::<S, T, false>(input)
}
#[inline]
pub(crate) fn parse_unsigned<S, T>(input: &[u8]) -> Result<(T, usize), Error>
where
S: Syntax,
T: Unsigned,
{
unsigned::<S, T, true>(input)
}
#[inline]
pub(crate) fn parse_signed_base<S, T>(input: &[u8]) -> Result<(T, usize), Error>
where
S: Syntax,
T: Signed,
{
signed::<S, T, false>(input)
}
#[inline]
pub(crate) fn parse_signed<S, T>(input: &[u8]) -> Result<(T, usize), Error>
where
S: Syntax,
T: Signed,
{
signed::<S, T, true>(input)
}
#[inline]
fn unsigned<S, T, const FULL: bool>(input: &[u8]) -> Result<(T, usize), Error>
where
S: Syntax,
T: Unsigned,
{
if let Some(b'-') = input.first() {
return Err(Error::new(0, ErrorKind::Unexpected(Expected::Number, b'-')));
}
let mut s = Scan::new(input);
let value = whole::<S, T, FULL>(&mut s)?;
Ok((value, s.at))
}
#[inline]
fn signed<S, T, const FULL: bool>(input: &[u8]) -> Result<(T, usize), Error>
where
S: Syntax,
T: Signed,
{
let mut s = Scan::new(input);
let negative = matches!(input.first(), Some(b'-'));
let value = whole::<S, T::Unsigned, FULL>(&mut s)?;
let value = if negative {
value.negate()
} else {
value.signed()
};
match value {
Some(value) => Ok((value, s.at)),
None => Err(Error::new(0, ErrorKind::Overflow)),
}
}
#[inline]
fn whole<S, T, const FULL: bool>(s: &mut Scan<'_>) -> Result<T, Error>
where
S: Syntax,
T: Unsigned,
{
let head = head::<S, T, FULL>(s)?;
if !head.more {
if head.overflow {
return Err(Error::new(0, ErrorKind::Overflow));
}
return Ok(head.value);
}
let tail = tail::<T>(s, head.len)?;
combine(head, tail)
}
#[inline]
pub(crate) fn parse_float<S, F>(input: &[u8]) -> Result<(F, usize), Error>
where
S: Syntax,
F: Float,
{
if S::HEX {
let mut s = Scan::new(input);
let negative = sign::<S>(&mut s);
if s.eat_hex_prefix() {
let out = digits::<u128, 16, true>(&mut s);
if out.len == 0 {
return Err(s.expected(Expected::Hex));
}
if out.overflow {
return Err(Error::new(0, ErrorKind::Overflow));
}
let value = F::from_u128(out.value);
return Ok((if negative { -value } else { value }, s.at));
}
}
match dec2flt(input) {
Some((value, len)) => Ok((value, len)),
None => Err(explain::<S>(input)),
}
}
#[inline]
pub(crate) fn parse_any<S>(input: &[u8]) -> Result<(Any, usize), Error>
where
S: Syntax,
{
let mut s = Scan::new(input);
let head = head::<S, u128, true>(&mut s)?;
let negative = head.negative;
let value = if head.more {
let tail = tail::<u128>(&mut s, head.len)?;
combine(head, tail)
} else if head.overflow {
Err(Error::new(0, ErrorKind::Overflow))
} else {
Ok(head.value)
};
let len = s.at;
let any = match value {
Ok(value) if negative => value.negate().map(Any::Signed),
Ok(value) => Some(Any::Unsigned(value)),
Err(..) => None,
};
if let Some(any) = any {
return Ok((any, len));
}
let (value, _) = parse_float::<S, f64>(&input[..len])?;
Ok((Any::Float(value), len))
}
#[inline]
pub(crate) fn skip<S>(input: &[u8]) -> Result<usize, Error>
where
S: Syntax,
{
let mut s = Scan::new(input);
let head = head::<S, u128, true>(&mut s)?;
if head.more {
tail::<u128>(&mut s, head.len)?;
}
Ok(s.at)
}
#[cold]
#[inline(never)]
fn explain<S>(input: &[u8]) -> Error
where
S: Syntax,
{
match skip::<S>(input) {
Ok(..) => Error::new(0, ErrorKind::Float),
Err(error) => error,
}
}
struct Scan<'a> {
input: &'a [u8],
at: usize,
}
impl<'a> Scan<'a> {
#[inline]
fn new(input: &'a [u8]) -> Self {
Self { input, at: 0 }
}
#[inline]
fn peek(&self) -> Option<u8> {
self.input.get(self.at).copied()
}
#[inline]
fn eat(&mut self, b: u8) -> bool {
if self.peek() == Some(b) {
self.at += 1;
true
} else {
false
}
}
#[inline]
fn eat_hex_prefix(&mut self) -> bool {
if matches!(self.input.get(self.at), Some(b'0'))
&& matches!(self.input.get(self.at + 1), Some(b'x' | b'X'))
{
self.at += 2;
true
} else {
false
}
}
#[inline]
fn expected(&self, expected: Expected) -> Error {
match self.peek() {
Some(b) => Error::new(self.at, ErrorKind::Unexpected(expected, b)),
None => Error::new(self.at, ErrorKind::Eof(expected)),
}
}
}
#[derive(Clone, Copy)]
struct Head<T> {
negative: bool,
value: T,
len: usize,
overflow: bool,
more: bool,
}
#[inline]
fn head<S, T, const FULL: bool>(s: &mut Scan<'_>) -> Result<Head<T>, Error>
where
S: Syntax,
T: Unsigned,
{
let negative = sign::<S>(s);
if S::HEX && s.eat_hex_prefix() {
let out = digits::<T, 16, true>(s);
if out.len == 0 {
return Err(s.expected(Expected::Hex));
}
return Ok(Head {
negative,
value: out.value,
len: out.len,
overflow: out.overflow,
more: false,
});
}
let zero = matches!(s.peek(), Some(b'0'));
let out = digits::<T, 10, true>(s);
if out.len == 0 {
if !(S::LEADING_POINT && matches!(s.peek(), Some(b'.'))) {
return Err(s.expected(Expected::Number));
}
} else if zero && out.len > 1 && !S::LEADING_ZEROS {
return Err(Error::new(s.at - out.len, ErrorKind::LeadingZero));
}
Ok(Head {
negative,
value: out.value,
len: out.len,
overflow: out.overflow,
more: FULL && matches!(s.peek(), Some(b'.' | b'e' | b'E')),
})
}
struct Tail<T> {
m: Mantissa<T>,
at: usize,
len: usize,
e: i32,
overflow: bool,
exponent: bool,
}
fn tail<T>(s: &mut Scan<'_>, base_len: usize) -> Result<Tail<T>, Error>
where
T: Unsigned,
{
let mut out = Tail {
m: Mantissa::ZERO,
at: s.at,
len: 0,
e: 0,
overflow: false,
exponent: false,
};
if s.eat(b'.') {
out.at = s.at;
let (m, len, overflow) = fraction::<T>(s);
if len == 0 && base_len == 0 {
return Err(s.expected(Expected::Fraction));
}
out.m = m;
out.len = len;
out.overflow = overflow;
}
if matches!(s.peek(), Some(b'e' | b'E')) {
s.at += 1;
let (e, overflow) = exponent(s)?;
out.e = e;
out.exponent = overflow;
}
Ok(out)
}
fn combine<T>(head: Head<T>, tail: Tail<T>) -> Result<T, Error>
where
T: Unsigned,
{
if tail.exponent {
return Err(Error::new(0, ErrorKind::ExponentOverflow));
}
if head.overflow || tail.overflow {
return Err(Error::new(0, ErrorKind::Overflow));
}
let mut base = head.value;
let Tail { m, e, .. } = tail;
let overflow = || Error::new(0, ErrorKind::Overflow);
let fraction = || Error::new(if tail.len > 0 { tail.at } else { 0 }, ErrorKind::Fraction);
if e == 0 {
if !m.value.is_zero() {
return Err(fraction());
}
return Ok(base);
}
if e > 0 {
let Some(exp) = e.checked_sub(m.exp).filter(|n| *n >= 0) else {
return Err(fraction());
};
if !base.is_zero() {
let Some(value) = base.checked_pow10(e as u32) else {
return Err(overflow());
};
base = value;
}
let value = m
.value
.checked_pow10(exp as u32)
.and_then(|m| base.checked_add(m));
match value {
Some(value) => Ok(value),
None => Err(overflow()),
}
} else if !m.value.is_zero() {
Err(fraction())
} else {
match base.checked_neg_pow10(e.unsigned_abs()) {
Some(value) => Ok(value),
None => Err(fraction()),
}
}
}
#[derive(Clone, Copy)]
struct Mantissa<T> {
value: T,
exp: i32,
}
impl<T> Mantissa<T>
where
T: Unsigned,
{
const ZERO: Self = Self {
value: T::ZERO,
exp: 0,
};
}
#[inline]
fn sign<S>(s: &mut Scan<'_>) -> bool
where
S: Syntax,
{
match s.peek() {
Some(b'-') => {
s.at += 1;
true
}
Some(b'+') if S::PLUS => {
s.at += 1;
false
}
_ => false,
}
}
fn fraction<T>(s: &mut Scan<'_>) -> (Mantissa<T>, usize, bool)
where
T: Unsigned,
{
let start = s.at;
let mut at = start;
let mut end = start;
while let Some(&b) = s.input.get(at) {
if !b.is_ascii_digit() {
break;
}
at += 1;
if b != b'0' {
end = at;
}
}
s.at = at;
let mut significant = Scan {
input: &s.input[..end],
at: start,
};
let out = digits::<T, 10, false>(&mut significant);
let m = Mantissa {
value: out.value,
exp: i32::try_from(out.len).unwrap_or(i32::MAX),
};
(m, at - start, out.overflow)
}
fn exponent(s: &mut Scan<'_>) -> Result<(i32, bool), Error> {
let negative = matches!(s.peek(), Some(b'-'));
if matches!(s.peek(), Some(b'-' | b'+')) {
s.at += 1;
}
let out = digits::<u32, 10, false>(s);
if out.len == 0 {
return Err(s.expected(Expected::Exponent));
}
let saturated = if negative { i32::MIN } else { i32::MAX };
if out.overflow {
return Ok((saturated, true));
}
match if negative {
out.value.negate()
} else {
out.value.signed()
} {
Some(e) => Ok((e, false)),
None => Ok((saturated, true)),
}
}
struct Digits<T> {
value: T,
len: usize,
overflow: bool,
}
#[inline]
fn digits<T, const RADIX: u32, const WORDS: bool>(s: &mut Scan<'_>) -> Digits<T>
where
T: Unsigned,
{
let buf = s.input;
let start = s.at;
let mut at = start;
let mut value = T::ZERO;
let unchecked = buf.len().min(at + T::max_safe_digits::<RADIX>());
if const { WORDS && size_of::<T>() >= 4 } {
while at + 8 <= unchecked {
let word = swar::word(buf, at);
let Some(digits) = (if RADIX == 16 {
swar::hex8(word)
} else {
swar::dec8(word)
}) else {
break;
};
value = value.wrapping_mul_add8::<RADIX>(digits);
at += 8;
}
}
while at < unchecked {
let Some(digit) = digit::<RADIX>(buf[at]) else {
s.at = at;
return Digits {
value,
len: at - start,
overflow: false,
};
};
value = value.wrapping_mul_add::<RADIX>(digit);
at += 1;
}
let mut overflow = false;
while let Some(digit) = buf.get(at).copied().and_then(digit::<RADIX>) {
if !overflow {
match value.checked_mul_add::<RADIX>(digit) {
Some(value_) => value = value_,
None => overflow = true,
}
}
at += 1;
}
s.at = at;
Digits {
value,
len: at - start,
overflow,
}
}
#[inline]
pub(super) fn digit<const RADIX: u32>(b: u8) -> Option<u8> {
if RADIX == 16 {
return hex_digit(b);
}
match b {
b'0'..=b'9' => Some(b - b'0'),
_ => None,
}
}
#[inline]
fn hex_digit(b: u8) -> Option<u8> {
let decimal = b.wrapping_sub(b'0');
let letter = (b | 0x20).wrapping_sub(b'a');
let is_letter = letter < 6;
let value = if is_letter { letter + 10 } else { decimal };
if is_letter | (decimal < 10) {
Some(value)
} else {
None
}
}