2018-09-09 17:13:58 +08:00
|
|
|
use fst::Automaton;
|
2018-12-03 21:39:56 +08:00
|
|
|
use lazy_static::lazy_static;
|
2018-09-09 17:13:58 +08:00
|
|
|
use levenshtein_automata::{
|
|
|
|
LevenshteinAutomatonBuilder as LevBuilder,
|
|
|
|
DFA, Distance,
|
|
|
|
};
|
|
|
|
|
|
|
|
lazy_static! {
|
|
|
|
static ref LEVDIST0: LevBuilder = LevBuilder::new(0, false);
|
|
|
|
static ref LEVDIST1: LevBuilder = LevBuilder::new(1, false);
|
|
|
|
static ref LEVDIST2: LevBuilder = LevBuilder::new(2, false);
|
|
|
|
}
|
|
|
|
|
|
|
|
pub struct DfaExt {
|
|
|
|
query_len: usize,
|
|
|
|
automaton: DFA,
|
|
|
|
}
|
|
|
|
|
2018-09-09 19:35:12 +08:00
|
|
|
impl Automaton for DfaExt {
|
|
|
|
type State = <DFA as Automaton>::State;
|
2018-09-09 17:13:58 +08:00
|
|
|
|
2018-09-09 19:35:12 +08:00
|
|
|
fn start(&self) -> Self::State {
|
|
|
|
self.automaton.start()
|
|
|
|
}
|
|
|
|
|
|
|
|
fn is_match(&self, state: &Self::State) -> bool {
|
|
|
|
self.automaton.is_match(state)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn can_match(&self, state: &Self::State) -> bool {
|
|
|
|
self.automaton.can_match(state)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn will_always_match(&self, state: &Self::State) -> bool {
|
|
|
|
self.automaton.will_always_match(state)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn accept(&self, state: &Self::State, byte: u8) -> Self::State {
|
|
|
|
self.automaton.accept(state, byte)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl AutomatonExt for DfaExt {
|
|
|
|
fn eval<B: AsRef<[u8]>>(&self, s: B) -> Distance {
|
|
|
|
self.automaton.eval(s)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn query_len(&self) -> usize {
|
|
|
|
self.query_len
|
2018-09-09 17:13:58 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-10-21 22:42:19 +08:00
|
|
|
enum PrefixSetting {
|
|
|
|
Prefix,
|
|
|
|
NoPrefix,
|
|
|
|
}
|
|
|
|
|
|
|
|
fn build_dfa_with_setting(query: &str, setting: PrefixSetting) -> DfaExt {
|
|
|
|
use self::PrefixSetting::{Prefix, NoPrefix};
|
|
|
|
|
2018-09-09 17:13:58 +08:00
|
|
|
let dfa = match query.len() {
|
2018-10-21 22:42:19 +08:00
|
|
|
0 ..= 4 => match setting {
|
|
|
|
Prefix => LEVDIST0.build_prefix_dfa(query),
|
|
|
|
NoPrefix => LEVDIST0.build_dfa(query),
|
|
|
|
},
|
|
|
|
5 ..= 8 => match setting {
|
|
|
|
Prefix => LEVDIST1.build_prefix_dfa(query),
|
|
|
|
NoPrefix => LEVDIST1.build_dfa(query),
|
|
|
|
},
|
|
|
|
_ => match setting {
|
|
|
|
Prefix => LEVDIST2.build_prefix_dfa(query),
|
|
|
|
NoPrefix => LEVDIST2.build_dfa(query),
|
|
|
|
},
|
2018-09-09 17:13:58 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
DfaExt { query_len: query.len(), automaton: dfa }
|
|
|
|
}
|
|
|
|
|
2018-10-21 22:42:19 +08:00
|
|
|
pub fn build_prefix_dfa(query: &str) -> DfaExt {
|
|
|
|
build_dfa_with_setting(query, PrefixSetting::Prefix)
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn build_dfa(query: &str) -> DfaExt {
|
|
|
|
build_dfa_with_setting(query, PrefixSetting::NoPrefix)
|
|
|
|
}
|
|
|
|
|
2018-09-09 17:13:58 +08:00
|
|
|
pub trait AutomatonExt: Automaton {
|
|
|
|
fn eval<B: AsRef<[u8]>>(&self, s: B) -> Distance;
|
|
|
|
fn query_len(&self) -> usize;
|
|
|
|
}
|