#[derive(Copy, Clone)]
struct CharType(u8);
impl CharType {
const IS_KEY_PART: Self = Self(0b0001);
const IS_KEY_START: Self = Self(0b0010);
const IS_SIMPLE_WS: Self = Self(0b0100);
const FLAGS_LEN: u32 = 3;
#[inline]
const fn bits(self) -> u8 {
self.0
}
#[inline]
const fn with_len(self, len: u8) -> u8 {
self.0 | (len << Self::FLAGS_LEN)
}
}
const CHAR_TABLE: [u8; 256] = {
let mut table = [0u8; 256];
table[b' ' as usize] = CharType::IS_SIMPLE_WS.with_len(1);
table[b'\t' as usize] = CharType::IS_SIMPLE_WS.with_len(4);
table[b'\r' as usize] = CharType::IS_SIMPLE_WS.with_len(1);
let starts = concat!(
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"$",
)
.as_bytes();
let mut i = 0;
while i < starts.len() {
table[starts[i] as usize] = CharType::IS_KEY_START.bits();
i += 1;
}
let parts = concat!(
"abcdefghijklmnopqrstuvwxyz",
"ABCDEFGHIJKLMNOPQRSTUVWXYZ",
"0123456789",
"-_.$",
)
.as_bytes();
let mut i = 0;
while i < parts.len() {
table[parts[i] as usize] = CharType::IS_KEY_PART.bits();
i += 1;
}
table
};
pub trait CharExt {
#[must_use]
#[allow(clippy::wrong_self_convention)] fn is_simple_ws(self) -> bool;
#[must_use]
fn simple_ws_len(self) -> u8;
}
impl CharExt for u8 {
#[inline]
fn is_simple_ws(self) -> bool {
(CHAR_TABLE[self as usize] & CharType::IS_SIMPLE_WS.bits()) != 0
}
#[inline]
fn simple_ws_len(self) -> u8 {
CHAR_TABLE[self as usize] >> CharType::FLAGS_LEN
}
}
pub trait SliceExt<'a> {
fn trim_simple_ws(self) -> Self;
}
impl<'a> SliceExt<'a> for &'a [u8] {
fn trim_simple_ws(mut self) -> Self {
while let [first, rest @ ..] = self {
if first.is_simple_ws() {
self = rest;
} else {
break;
}
}
while let [rest @ .., last] = self {
if last.is_simple_ws() {
self = rest;
} else {
break;
}
}
self
}
}