use crate::rfc9110::chars::{CR, LF};
#[inline]
pub(crate) fn position(bytes: &[u8], hit: impl Fn(u8) -> bool) -> Option<usize> {
let (blocks, tail) = bytes.as_chunks::<16>();
for (i, block) in blocks.iter().enumerate() {
let mut mask = 0u16;
for (j, &b) in block.iter().enumerate() {
mask |= u16::from(hit(b)) << j;
}
if mask != 0 {
return Some(i * 16 + mask.trailing_zeros() as usize);
}
}
tail.iter()
.position(|&b| hit(b))
.map(|j| blocks.len() * 16 + j)
}
#[inline]
pub(crate) fn crlf_position(bytes: &[u8]) -> Option<usize> {
let mut from = 1;
loop {
let lf = from + position(bytes.get(from..)?, |b| b == LF)?;
if bytes[lf - 1] == CR {
return Some(lf - 1);
}
from = lf + 1;
}
}
#[cfg(test)]
mod tests {
use crate::scan::*;
#[test]
fn position_across_blocks_and_tail() {
let mut bytes = [b'a'; 40];
for at in 0..bytes.len() {
bytes[at] = b':';
assert_eq!(position(&bytes, |b| b == b':'), Some(at));
bytes[at] = b'a';
}
assert_eq!(position(&bytes, |b| b == b':'), None);
}
#[test]
fn crlf_position_skips_bare_line_feeds() {
assert_eq!(crlf_position(b"\n5\nab\r\n"), Some(5));
assert_eq!(crlf_position(b"\r\r\n"), Some(1));
assert_eq!(crlf_position(b"\n\r"), None);
assert_eq!(crlf_position(b""), None);
}
}