use ahocorasick::MatchKind;
use prefilter::{self, Candidate, Prefilter, PrefilterState};
use state_id::{dead_id, fail_id, StateID};
use Match;
pub trait Automaton {
type ID: StateID;
fn match_kind(&self) -> &MatchKind;
fn anchored(&self) -> bool;
fn prefilter(&self) -> Option<&dyn Prefilter>;
fn start_state(&self) -> Self::ID;
fn is_valid(&self, id: Self::ID) -> bool;
fn is_match_state(&self, id: Self::ID) -> bool;
fn is_match_or_dead_state(&self, id: Self::ID) -> bool {
id == dead_id() || self.is_match_state(id)
}
fn get_match(
&self,
id: Self::ID,
match_index: usize,
end: usize,
) -> Option<Match>;
fn match_count(&self, id: Self::ID) -> usize;
fn next_state(&self, current: Self::ID, input: u8) -> Self::ID;
fn next_state_no_fail(&self, current: Self::ID, input: u8) -> Self::ID {
let next = self.next_state(current, input);
debug_assert!(
next != fail_id(),
"automaton should never return fail_id for next state"
);
next
}
#[inline(always)]
fn standard_find_at(
&self,
prestate: &mut PrefilterState,
haystack: &[u8],
at: usize,
state_id: &mut Self::ID,
) -> Option<Match> {
if let Some(pre) = self.prefilter() {
self.standard_find_at_imp(
prestate,
Some(pre),
haystack,
at,
state_id,
)
} else {
self.standard_find_at_imp(prestate, None, haystack, at, state_id)
}
}
#[inline(always)]
fn standard_find_at_imp(
&self,
prestate: &mut PrefilterState,
prefilter: Option<&dyn Prefilter>,
haystack: &[u8],
mut at: usize,
state_id: &mut Self::ID,
) -> Option<Match> {
while at < haystack.len() {
if let Some(pre) = prefilter {
if prestate.is_effective(at) && *state_id == self.start_state()
{
let c = prefilter::next(prestate, pre, haystack, at)
.into_option();
match c {
None => return None,
Some(i) => {
at = i;
}
}
}
}
*state_id = self.next_state_no_fail(*state_id, haystack[at]);
at += 1;
debug_assert!(
*state_id != dead_id() || self.anchored(),
"standard find should never see a dead state"
);
if self.is_match_or_dead_state(*state_id) {
return if *state_id == dead_id() {
None
} else {
self.get_match(*state_id, 0, at)
};
}
}
None
}
#[inline(never)]
fn leftmost_find_at(
&self,
prestate: &mut PrefilterState,
haystack: &[u8],
at: usize,
state_id: &mut Self::ID,
) -> Option<Match> {
if let Some(pre) = self.prefilter() {
self.leftmost_find_at_imp(
prestate,
Some(pre),
haystack,
at,
state_id,
)
} else {
self.leftmost_find_at_imp(prestate, None, haystack, at, state_id)
}
}
#[inline(always)]
fn leftmost_find_at_imp(
&self,
prestate: &mut PrefilterState,
prefilter: Option<&dyn Prefilter>,
haystack: &[u8],
mut at: usize,
state_id: &mut Self::ID,
) -> Option<Match> {
debug_assert!(self.match_kind().is_leftmost());
if self.anchored() && at > 0 && *state_id == self.start_state() {
return None;
}
let mut last_match = self.get_match(*state_id, 0, at);
while at < haystack.len() {
if let Some(pre) = prefilter {
if prestate.is_effective(at) && *state_id == self.start_state()
{
let c = prefilter::next(prestate, pre, haystack, at)
.into_option();
match c {
None => return None,
Some(i) => {
at = i;
}
}
}
}
*state_id = self.next_state_no_fail(*state_id, haystack[at]);
at += 1;
if self.is_match_or_dead_state(*state_id) {
if *state_id == dead_id() {
debug_assert!(
last_match.is_some() || self.anchored(),
"failure state should only be seen after match"
);
return last_match;
}
last_match = self.get_match(*state_id, 0, at);
}
}
last_match
}
#[inline(never)]
fn leftmost_find_at_no_state(
&self,
prestate: &mut PrefilterState,
haystack: &[u8],
at: usize,
) -> Option<Match> {
if let Some(pre) = self.prefilter() {
self.leftmost_find_at_no_state_imp(
prestate,
Some(pre),
haystack,
at,
)
} else {
self.leftmost_find_at_no_state_imp(prestate, None, haystack, at)
}
}
#[inline(always)]
fn leftmost_find_at_no_state_imp(
&self,
prestate: &mut PrefilterState,
prefilter: Option<&dyn Prefilter>,
haystack: &[u8],
mut at: usize,
) -> Option<Match> {
debug_assert!(self.match_kind().is_leftmost());
if self.anchored() && at > 0 {
return None;
}
if let Some(pre) = prefilter {
debug_assert!(!self.anchored());
if !pre.reports_false_positives() {
return match pre.next_candidate(prestate, haystack, at) {
Candidate::None => None,
Candidate::Match(m) => Some(m),
Candidate::PossibleStartOfMatch(_) => unreachable!(),
};
}
}
let mut state_id = self.start_state();
let mut last_match = self.get_match(state_id, 0, at);
while at < haystack.len() {
if let Some(pre) = prefilter {
if prestate.is_effective(at) && state_id == self.start_state()
{
match prefilter::next(prestate, pre, haystack, at) {
Candidate::None => return None,
Candidate::Match(m) => return Some(m),
Candidate::PossibleStartOfMatch(i) => {
at = i;
}
}
}
}
state_id = self.next_state_no_fail(state_id, haystack[at]);
at += 1;
if self.is_match_or_dead_state(state_id) {
if state_id == dead_id() {
debug_assert!(
last_match.is_some() || self.anchored(),
"failure state should only be seen after match"
);
return last_match;
}
last_match = self.get_match(state_id, 0, at);
}
}
last_match
}
#[inline(always)]
fn overlapping_find_at(
&self,
prestate: &mut PrefilterState,
haystack: &[u8],
at: usize,
state_id: &mut Self::ID,
match_index: &mut usize,
) -> Option<Match> {
if self.anchored() && at > 0 && *state_id == self.start_state() {
return None;
}
let match_count = self.match_count(*state_id);
if *match_index < match_count {
let result = self.get_match(*state_id, *match_index, at);
debug_assert!(result.is_some(), "must be a match");
*match_index += 1;
return result;
}
*match_index = 0;
match self.standard_find_at(prestate, haystack, at, state_id) {
None => None,
Some(m) => {
*match_index = 1;
Some(m)
}
}
}
#[inline(always)]
fn earliest_find_at(
&self,
prestate: &mut PrefilterState,
haystack: &[u8],
at: usize,
state_id: &mut Self::ID,
) -> Option<Match> {
if *state_id == self.start_state() {
if self.anchored() && at > 0 {
return None;
}
if let Some(m) = self.get_match(*state_id, 0, at) {
return Some(m);
}
}
self.standard_find_at(prestate, haystack, at, state_id)
}
#[inline(always)]
fn find_at(
&self,
prestate: &mut PrefilterState,
haystack: &[u8],
at: usize,
state_id: &mut Self::ID,
) -> Option<Match> {
match *self.match_kind() {
MatchKind::Standard => {
self.earliest_find_at(prestate, haystack, at, state_id)
}
MatchKind::LeftmostFirst | MatchKind::LeftmostLongest => {
self.leftmost_find_at(prestate, haystack, at, state_id)
}
MatchKind::__Nonexhaustive => unreachable!(),
}
}
#[inline(always)]
fn find_at_no_state(
&self,
prestate: &mut PrefilterState,
haystack: &[u8],
at: usize,
) -> Option<Match> {
match *self.match_kind() {
MatchKind::Standard => {
let mut state = self.start_state();
self.earliest_find_at(prestate, haystack, at, &mut state)
}
MatchKind::LeftmostFirst | MatchKind::LeftmostLongest => {
self.leftmost_find_at_no_state(prestate, haystack, at)
}
MatchKind::__Nonexhaustive => unreachable!(),
}
}
}