#![no_std]
#![warn(missing_docs)]
mod bit;
pub mod bits {
pub use crate::bit::{B0, B1, B2, B3, B4, B5, B6, B7};
}
use bit::Bit;
use bits::*;
use core::marker::PhantomData;
use core::ops::RangeInclusive;
type Chunk = usize;
pub const ASCII_RANGE_LEN: usize = 0x80;
pub const CHUNK_SIZE: usize = core::mem::size_of::<Chunk>();
pub const BITS_PER_CHUNK: usize = 8 * CHUNK_SIZE;
pub const CHUNKS: usize = ASCII_RANGE_LEN / BITS_PER_CHUNK;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AnyByteSet<const N: usize> {
mask: [Chunk; N],
}
pub type AsciiSet = AnyByteSet<CHUNKS>;
pub type ByteSet = AnyByteSet<{ 2 * CHUNKS }>;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct AnyByteStack<B, const N: usize> {
masks: [u8; N],
current: PhantomData<B>,
}
pub type AsciiStack<B = ()> = AnyByteStack<B, ASCII_RANGE_LEN>;
pub type ByteStack<B = ()> = AnyByteStack<B, { 2 * ASCII_RANGE_LEN }>;
impl AsciiSet {
pub const fn new() -> Self {
Self { mask: [0; CHUNKS] }
}
#[inline]
pub const fn contains(&self, byte: u8) -> bool {
if byte >= ASCII_RANGE_LEN as u8 {
return false;
};
let chunk = self.mask[byte as usize / BITS_PER_CHUNK];
let mask = 1 << (byte as usize % BITS_PER_CHUNK);
(chunk & mask) != 0
}
}
impl ByteSet {
pub const fn new() -> Self {
Self {
mask: [0; 2 * CHUNKS],
}
}
#[inline]
pub const fn contains(&self, byte: u8) -> bool {
let chunk = self.mask[byte as usize / BITS_PER_CHUNK];
let mask = 1 << (byte as usize % BITS_PER_CHUNK);
(chunk & mask) != 0
}
}
impl<const N: usize> AnyByteSet<N> {
pub const LOWERCASE: Self = Self::blank().add_range(b'a'..=b'z');
pub const UPPERCASE: Self = Self::blank().add_range(b'A'..=b'Z');
pub const DIGITS: Self = Self::blank().add_range(b'0'..=b'9');
pub const ALPHABETIC: Self = Self::LOWERCASE.union(Self::UPPERCASE);
pub const ALPHANUMERIC: Self = Self::ALPHABETIC.union(Self::DIGITS);
pub const SPACE_TAB: Self = Self::blank().add_bytes(b" \t");
pub const NEWLINE: Self = Self::blank().add_bytes(b"\r\n");
pub const WHITESPACE: Self = Self::SPACE_TAB.union(Self::NEWLINE);
pub const GRAPHIC: Self = Self::blank().add_range(b'!'..=b'~');
pub const URI_RESERVED: Self = Self::blank().add_bytes(b"!#$&'()*+,/:;=?@[]");
const fn blank() -> Self {
Self { mask: [0; N] }
}
pub const fn add(&self, byte: u8) -> Self {
let mut mask = self.mask;
mask[byte as usize / BITS_PER_CHUNK] |= 1 << (byte as usize % BITS_PER_CHUNK);
Self { mask }
}
pub const fn remove(&self, byte: u8) -> Self {
let mut mask = self.mask;
mask[byte as usize / BITS_PER_CHUNK] &= !(1 << (byte as usize % BITS_PER_CHUNK));
Self { mask }
}
pub const fn add_bytes(&self, bytes: &[u8]) -> Self {
let mut aset = *self;
let mut i = 0;
while i < bytes.len() {
aset = aset.add(bytes[i]);
i += 1;
}
aset
}
pub const fn remove_bytes(&self, bytes: &[u8]) -> Self {
let mut aset = *self;
let mut i = 0;
while i < bytes.len() {
aset = aset.remove(bytes[i]);
i += 1;
}
aset
}
pub const fn add_range(&self, range: RangeInclusive<u8>) -> Self {
let mut aset = *self;
let mut c = *range.start();
while c <= *range.end() {
aset = aset.add(c);
c += 1;
}
aset
}
pub const fn remove_range(&self, range: RangeInclusive<u8>) -> Self {
let mut aset = *self;
let mut c = *range.start();
while c <= *range.end() {
aset = aset.remove(c);
c += 1;
}
aset
}
pub const fn union<const M: usize>(&self, other: AnyByteSet<M>) -> Self {
let mut mask = [0; N];
let mut i = 0;
while i < N {
mask[i] = self.mask[i] | other.mask[i];
i += 1;
}
Self { mask }
}
pub const fn intersection<const M: usize>(&self, other: AnyByteSet<M>) -> Self {
let mut mask = [0; N];
let mut i = 0;
while i < N {
mask[i] = self.mask[i] & other.mask[i];
i += 1;
}
Self { mask }
}
pub const fn complement(&self) -> Self {
let mut mask = self.mask;
let mut i = 0;
while i < N {
mask[i] = !mask[i];
i += 1;
}
Self { mask }
}
pub const fn difference<const M: usize>(&self, other: AnyByteSet<M>) -> Self {
self.intersection(other.complement())
}
}
impl<T> AsciiStack<T> {
#[inline]
pub fn contains<B: Bit>(&self, byte: u8) -> bool {
byte < ASCII_RANGE_LEN as u8 && self.masks[byte as usize] & (1 << B::NUMBER) != 0
}
}
impl AsciiStack<B0> {
pub const fn new() -> Self {
Self {
masks: [0; ASCII_RANGE_LEN],
current: PhantomData,
}
}
}
impl<T> ByteStack<T> {
#[inline]
pub fn contains<B: Bit>(&self, byte: u8) -> bool {
self.masks[byte as usize] & (1 << B::NUMBER) != 0
}
}
impl ByteStack<B0> {
pub const fn new() -> Self {
Self {
masks: [0; 2 * ASCII_RANGE_LEN],
current: PhantomData,
}
}
}
macro_rules! implement_add_set {
($($ty:ty),*) => {
$(impl<const N: usize> AnyByteStack<$ty, N> {
pub const fn add_set<const M: usize>(
&self,
aset: AnyByteSet<M>,
) -> AnyByteStack<<$ty as Bit>::Successor, N> {
let mut masks = self.masks;
let mask = aset.mask;
let mut i = 0;
while i < M {
let mut j = 0;
while j < BITS_PER_CHUNK {
if mask[i] & (1 << j) != 0 {
masks[i * BITS_PER_CHUNK + j] |= 1 << <$ty>::NUMBER;
}
j += 1;
}
i += 1;
}
AnyByteStack {
masks,
current: PhantomData,
}
}
})*
}
}
implement_add_set!(B0, B1, B2, B3, B4, B5, B6, B7);