use std::fmt;
use memchr::{memchr, memchr2, memchr3};
pub trait Prefilter: Send + Sync + fmt::Debug {
fn next_candidate(&self, haystack: &[u8], at: usize) -> Option<usize>;
fn clone_prefilter(&self) -> Box<Prefilter>;
}
#[derive(Debug)]
pub struct PrefilterObj(Box<Prefilter>);
impl Clone for PrefilterObj {
fn clone(&self) -> Self {
PrefilterObj(self.0.clone_prefilter())
}
}
impl PrefilterObj {
pub fn new<T: Prefilter + 'static>(t: T) -> PrefilterObj {
PrefilterObj(Box::new(t))
}
pub fn as_ref(&self) -> &Prefilter {
&*self.0
}
}
#[derive(Clone, Debug)]
pub struct StartBytesBuilder {
byteset: Vec<bool>,
}
impl StartBytesBuilder {
pub fn new() -> StartBytesBuilder {
StartBytesBuilder { byteset: vec![false; 256] }
}
pub fn build(&self) -> Option<PrefilterObj> {
let (mut bytes, mut len) = ([0; 3], 0);
for b in 0..256 {
if !self.byteset[b] {
continue;
}
if len == 3 {
return None;
}
if b > 0x7F {
return None;
}
bytes[len] = b as u8;
len += 1;
}
match len {
0 => None,
1 => {
Some(PrefilterObj::new(StartBytesOne {
byte1: bytes[0],
}))
}
2 => {
Some(PrefilterObj::new(StartBytesTwo {
byte1: bytes[0],
byte2: bytes[1],
}))
}
3 => {
Some(PrefilterObj::new(StartBytesThree {
byte1: bytes[0],
byte2: bytes[1],
byte3: bytes[2],
}))
}
_ => unreachable!(),
}
}
pub fn add(&mut self, byte: u8) {
self.byteset[byte as usize] = true;
}
}
#[derive(Clone, Debug)]
pub struct StartBytesOne {
byte1: u8,
}
impl Prefilter for StartBytesOne {
fn next_candidate(&self, haystack: &[u8], at: usize) -> Option<usize> {
memchr(self.byte1, &haystack[at..])
.map(|i| at + i)
}
fn clone_prefilter(&self) -> Box<Prefilter> {
Box::new(self.clone())
}
}
#[derive(Clone, Debug)]
pub struct StartBytesTwo {
byte1: u8,
byte2: u8,
}
impl Prefilter for StartBytesTwo {
fn next_candidate(&self, haystack: &[u8], at: usize) -> Option<usize> {
memchr2(self.byte1, self.byte2, &haystack[at..])
.map(|i| at + i)
}
fn clone_prefilter(&self) -> Box<Prefilter> {
Box::new(self.clone())
}
}
#[derive(Clone, Debug)]
pub struct StartBytesThree {
byte1: u8,
byte2: u8,
byte3: u8,
}
impl Prefilter for StartBytesThree {
fn next_candidate(&self, haystack: &[u8], at: usize) -> Option<usize> {
memchr3(self.byte1, self.byte2, self.byte3, &haystack[at..])
.map(|i| at + i)
}
fn clone_prefilter(&self) -> Box<Prefilter> {
Box::new(self.clone())
}
}