use super::lexical::is_step_space;
#[inline]
pub fn step_numeric_literal_len(bytes: &[u8]) -> Option<usize> {
let digits_from = |mut i: usize| {
while bytes.get(i).is_some_and(u8::is_ascii_digit) {
i += 1;
}
i
};
let mut i = usize::from(matches!(bytes.first(), Some(b'+' | b'-')));
let int_end = digits_from(i);
let mut digits = int_end - i;
i = int_end;
if bytes.get(i) == Some(&b'.') {
let frac_end = digits_from(i + 1);
digits += frac_end - (i + 1);
i = frac_end;
}
if digits == 0 {
return None;
}
if matches!(bytes.get(i), Some(b'e' | b'E')) {
let exp_start = i + 1 + usize::from(matches!(bytes.get(i + 1), Some(b'+' | b'-')));
let exp_end = digits_from(exp_start);
if exp_end == exp_start {
return None;
}
i = exp_end;
}
match bytes.get(i) {
None => Some(i),
Some(&b) if b == b',' || b == b')' || is_step_space(b) => Some(i),
Some(&b'/') if bytes.get(i + 1) == Some(&b'*') => Some(i),
_ => None,
}
}
#[inline]
pub fn parse_step_numeric<T: fast_float2::FastFloat>(bytes: &[u8]) -> Option<(T, usize)> {
let len = step_numeric_literal_len(bytes)?;
fast_float2::parse::<T, _>(&bytes[..len]).ok().map(|v| (v, len))
}
#[cfg(test)]
#[path = "numeric_literal_tests.rs"]
mod tests;