pub(crate) struct Invalid {
pub byte: u8,
}
pub(crate) const fn validate(bytes: &[u8]) -> Result<(), Invalid> {
let mut index = 0;
while index < bytes.len() {
let byte = bytes[index];
if !is_rfc_token_char(byte) {
return Err(Invalid { byte });
}
index += 1;
}
Ok(())
}
const fn is_rfc_token_char(b: u8) -> bool {
matches!(b, b'!'
| b'#'
| b'$'
| b'%'
| b'&'
| b'\''
| b'*'
| b'+'
| b'-'
| b'.'
| b'^'
| b'_'
| b'`'
| b'|'
| b'~'
| b'0'..=b'9'
| b'A'..=b'Z'
| b'a'..=b'z'
)
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::BTreeSet;
const SPECIAL_TOKEN_CHARS: &[u8] = &[
b'!', b'#', b'$', b'%', b'&', b'\'', b'*', b'+', b'-', b'.', b'^', b'_', b'`', b'|', b'~',
];
fn rfc_token_chars() -> BTreeSet<u8> {
let digit_chars = b'0'..=b'9';
let uppercase = b'A'..=b'Z';
let lowercase = b'a'..=b'z';
SPECIAL_TOKEN_CHARS
.iter()
.copied()
.chain(digit_chars)
.chain(uppercase)
.chain(lowercase)
.collect()
}
fn not_rfc_token_chars() -> BTreeSet<u8> {
let t_chars = rfc_token_chars();
(u8::MIN..=u8::MAX)
.filter(|c| !t_chars.contains(c))
.collect()
}
#[test]
fn test_all_rfc_token_chars() {
for c in rfc_token_chars() {
print_char(c);
assert!(is_rfc_token_char(c));
}
}
#[test]
fn test_all_not_rfc_token_chars() {
for c in not_rfc_token_chars() {
print_char(c);
assert!(!is_rfc_token_char(c));
}
}
fn print_char(b: u8) {
println!("{}/'{}'", b, char::from(b));
}
}