#[inline]
pub fn skip_step_comment(bytes: &[u8], i: usize) -> Option<usize> {
if bytes.get(i) != Some(&b'/') || bytes.get(i + 1) != Some(&b'*') {
return None;
}
let len = bytes.len();
let mut p = i + 2;
while p + 1 < len {
let star = match memchr::memchr(b'*', &bytes[p..]) {
Some(off) => p + off,
None => return None, };
if star + 1 < len && bytes[star + 1] == b'/' {
return Some(star + 2);
}
p = star + 1;
}
None }
#[inline]
pub fn skip_step_trivia(bytes: &[u8], i: usize) -> Option<usize> {
let len = bytes.len();
let mut p = i;
loop {
while p < len && is_step_space(bytes[p]) {
p += 1;
}
if bytes.get(p) != Some(&b'/') || bytes.get(p + 1) != Some(&b'*') {
return Some(p);
}
p = skip_step_comment(bytes, p)?;
}
}
#[inline]
pub fn is_step_space(b: u8) -> bool {
matches!(b, b' ' | b'\t' | b'\n' | b'\r' | 0x0b | 0x0c)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn trivia_skips_a_run_of_whitespace_and_comments() {
let bytes = b" /* a */\t/* b */\n = X";
let end = skip_step_trivia(bytes, 0).expect("every comment closes");
assert_eq!(&bytes[end..], b"= X");
}
#[test]
fn trivia_stops_on_the_first_non_trivia_byte() {
assert_eq!(skip_step_trivia(b"=X", 0), Some(0));
assert_eq!(skip_step_trivia(b" /2", 0), Some(1));
}
#[test]
fn trivia_refuses_an_unterminated_comment() {
assert_eq!(skip_step_trivia(b" /* never closes", 0), None);
}
#[test]
fn trivia_skips_form_feed_and_vertical_tab() {
assert_eq!(skip_step_trivia(b"\x0c=X", 0), Some(1));
assert_eq!(skip_step_trivia(b"\x0b=X", 0), Some(1));
assert_eq!(skip_step_trivia(b"\x0c\x0b =X", 0), Some(3));
}
#[test]
fn closed_comment_skips_to_after_close() {
let bytes = b"/* hello #77 */rest";
assert_eq!(skip_step_comment(bytes, 0), Some(15));
assert_eq!(&bytes[15..], b"rest");
}
#[test]
fn adjacent_asterisks_inside_a_comment_do_not_confuse_the_scan() {
let bytes = b"/* a ** weird *comment* */tail";
let end = skip_step_comment(bytes, 0).expect("comment is closed");
assert_eq!(&bytes[end..], b"tail");
}
#[test]
fn unterminated_comment_is_refused() {
assert_eq!(skip_step_comment(b"/* never closes", 0), None);
assert_eq!(skip_step_comment(b"/*", 0), None);
assert_eq!(skip_step_comment(b"/* trailing star *", 0), None);
}
#[test]
fn not_a_comment_at_all() {
assert_eq!(skip_step_comment(b"/x not a comment", 0), None);
assert_eq!(skip_step_comment(b"/", 0), None);
assert_eq!(skip_step_comment(b"", 0), None);
}
}