use super::identifiers::IDENT_CONTINUE_LUT;
use super::token::{Token, TokenKind};
use crate::number::{continues_unit, exponent_len};
pub(crate) fn read_number_into(source: &str, pos: &mut usize, dst: &mut Token) {
let start = *pos;
let bytes = source.as_bytes();
let len = bytes.len();
let mut p = start;
if matches!(bytes.get(p), Some(b'-' | b'+')) {
p += 1;
}
let int_start = p;
while p < len && bytes[p].is_ascii_digit() {
p += 1;
}
let has_integer_digits = p > int_start;
if bytes.get(p) == Some(&b'.') {
let peek_char = source[p + 1..].chars().next();
if peek_char.is_some_and(|ch| ch.is_ascii_digit()) {
p += 1; while p < len && bytes[p].is_ascii_digit() {
p += 1;
}
} else if has_integer_digits
&& (exponent_len(&source[p + 1..]) > 0
|| peek_char.is_none_or(|ch| !continues_unit(ch)))
{
p += 1; }
}
if exponent_len(&source[p..]) > 0 {
p += 1; if matches!(bytes.get(p), Some(b'+' | b'-')) {
p += 1;
}
while p < len && bytes[p].is_ascii_digit() {
p += 1;
}
}
let num_end = p;
*pos = p;
debug_assert!(
source[start..num_end].parse::<f64>().is_ok(),
"read_number_into scanned a non-number: {:?}",
&source[start..num_end]
);
if bytes.get(p) == Some(&b'%') {
p += 1;
*pos = p;
*dst = Token {
kind: TokenKind::Percentage,
start: start as u32,
end: p as u32,
};
return;
}
if let Some(ch) = source[p..].chars().next()
&& (ch.is_alphabetic() || ch == '-')
{
let unit_start = p;
loop {
while p < len && IDENT_CONTINUE_LUT[bytes[p] as usize] {
p += 1;
}
match source[p..].chars().next() {
Some(ch) if ch.is_alphanumeric() || ch == '-' || ch == '_' => {
p += ch.len_utf8();
}
_ => break,
}
}
let unit_len = p - unit_start;
if unit_len > 0 {
*pos = p;
*dst = Token {
kind: TokenKind::Dimension {
unit_len: unit_len as u8,
},
start: start as u32,
end: p as u32,
};
return;
}
p = unit_start;
}
*pos = p;
*dst = Token {
kind: TokenKind::Number,
start: start as u32,
end: p as u32,
};
}