use crate::data::array_types;
use std::ops::{Index, RangeInclusive};
#[repr(transparent)]
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct ByteValidator([bool; 256]);
impl Default for ByteValidator {
#[inline]
fn default() -> Self {
Self([false; 256])
}
}
impl ByteValidator {
#[inline]
#[must_use]
pub const fn new(arr: [bool; 256]) -> Self {
Self(arr)
}
#[inline]
#[must_use]
pub const fn all() -> Self {
Self([true; 256])
}
#[inline]
#[must_use]
pub const fn none() -> Self {
Self([false; 256])
}
#[must_use]
pub const fn add<const S: usize>(self, bytes: &[u8; S]) -> Self {
assert!(
array_types::is_unique(bytes),
"Attempted to add a byte multiple times in the same call!"
);
self.set_bytes(bytes, true)
}
#[must_use]
pub const fn remove<const S: usize>(self, bytes: &[u8; S]) -> Self {
assert!(
array_types::is_unique(bytes),
"Attempted to remove a byte multiple times in the same call!"
);
self.set_bytes(bytes, false)
}
#[must_use]
pub const fn add_range(self, range: RangeInclusive<u8>) -> Self {
self.set_range(range, true)
}
#[must_use]
pub const fn remove_range(self, range: RangeInclusive<u8>) -> Self {
self.set_range(range, false)
}
#[inline]
#[must_use]
pub const fn into_inner(self) -> [bool; 256] {
self.0
}
const fn set_bytes<const S: usize>(mut self, bytes: &[u8; S], valid: bool) -> Self {
let mut i = 0;
while i < S {
self.set_byte(bytes[i], valid);
i += 1;
}
self
}
#[allow(clippy::cast_possible_truncation)]
const fn set_range(mut self, range: RangeInclusive<u8>, valid: bool) -> Self {
let from = *range.start() as usize..*range.end() as usize + 1;
let mut byte = from.start;
while byte < from.end {
self.set_byte(byte as u8, valid);
byte += 1;
}
self
}
#[inline]
pub(crate) const fn set_byte(&mut self, byte: u8, valid: bool) {
self.0[byte as usize] = valid;
}
#[allow(dead_code)]
pub(crate) const fn generate_alphabet<const N: usize>(&self) -> [u8; N] {
let mut out = [0; N];
let mut byte: u8 = 0;
let mut out_index = 0;
loop {
if self.0[byte as usize] {
assert!(out_index < out.len(), "Too small of N passed");
out[out_index] = byte;
out_index += 1;
}
match byte.checked_add(1) {
Some(next_byte) => byte = next_byte,
None => break,
}
}
assert!(out_index == N, "Too large of N passed");
out
}
}
impl Index<u8> for ByteValidator {
type Output = bool;
#[inline]
fn index(&self, index: u8) -> &bool {
&self.0[index as usize]
}
}