const CHUNK: usize = 8;
const HIGH_BITS: u64 = 0x8080_8080_8080_8080;
pub(crate) fn ascii_prefix_len(bytes: &[u8]) -> usize {
let mut offset = 0;
let (chunks, _) = bytes.as_chunks::<CHUNK>();
for chunk in chunks {
if u64::from_ne_bytes(*chunk) & HIGH_BITS != 0 {
break;
}
offset += CHUNK;
}
while offset < bytes.len() && bytes[offset] < 0x80 {
offset += 1;
}
offset
}
pub(crate) fn ascii_prefix_len_str(s: &str) -> usize {
ascii_prefix_len(s.as_bytes())
}
#[cfg(any(feature = "alloc", test))]
pub(crate) fn is_ascii(bytes: &[u8]) -> bool {
ascii_prefix_len(bytes) == bytes.len()
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn prefix_len() {
assert_eq!(ascii_prefix_len(b""), 0);
assert_eq!(ascii_prefix_len(b"hello"), 5);
assert_eq!(ascii_prefix_len(b"\x80"), 0);
assert_eq!(ascii_prefix_len(b"0123456789abcdef\x80"), 16);
assert_eq!(ascii_prefix_len(b"0123456\x80abcdef"), 7);
assert_eq!(ascii_prefix_len(b"0123456789\xC3\xA9"), 10);
}
#[test]
fn all_ascii() {
assert!(is_ascii(b"plain ascii text, all of it"));
assert!(!is_ascii("caf\u{E9}".as_bytes()));
}
}