const CHUNK: usize = 8;
const HIGH_BITS: u64 = 0x8080_8080_8080_8080;
#[inline]
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
}
#[inline]
pub(crate) fn ascii_prefix_len_capped(bytes: &[u8], limit: usize) -> usize {
if bytes.first().is_none_or(|&b| b >= 0x80) {
return 0;
}
ascii_prefix_len(&bytes[..core::cmp::min(bytes.len(), limit)])
}
#[cfg(feature = "shift-jis")]
#[inline]
pub(crate) fn jis_roman_prefix_len(bytes: &[u8], limit: usize) -> usize {
let run = ascii_prefix_len_capped(bytes, limit);
match bytes[..run].iter().position(|&b| b == 0x5C || b == 0x7E) {
Some(at) => at,
None => run,
}
}
#[inline]
#[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 the_cap_bounds_the_scan() {
let bytes = b"0123456789abcdef";
assert_eq!(ascii_prefix_len_capped(bytes, 4), 4);
assert_eq!(ascii_prefix_len_capped(bytes, 100), 16);
assert_eq!(ascii_prefix_len_capped(b"ab\x80cd", 100), 2);
assert_eq!(ascii_prefix_len_capped(b"", 8), 0);
}
#[cfg(feature = "shift-jis")]
#[test]
fn jis_roman_stops_at_the_yen_sign_and_the_overline() {
assert_eq!(jis_roman_prefix_len(b"plain text", 100), 10);
assert_eq!(jis_roman_prefix_len(b"C:\\dir", 100), 2);
assert_eq!(jis_roman_prefix_len(b"a~b", 100), 1);
assert_eq!(jis_roman_prefix_len(b"\\", 100), 0);
assert_eq!(jis_roman_prefix_len(b"abcdef", 3), 3);
assert_eq!(jis_roman_prefix_len(b"ab\xA1", 100), 2);
}
#[test]
fn all_ascii() {
assert!(is_ascii(b"plain ascii text, all of it"));
assert!(!is_ascii("caf\u{E9}".as_bytes()));
}
}