use crate::{
SupportLang,
constants::{EXTENSION_TO_LANG, EXTENSIONS},
};
use aho_corasick::{AhoCorasick, AhoCorasickBuilder, Anchored, Input, MatchKind, StartKind};
use std::sync::LazyLock;
static AHO_CORASICK: LazyLock<AhoCorasick> = LazyLock::new(|| {
AhoCorasickBuilder::new()
.match_kind(MatchKind::LeftmostLongest)
.start_kind(StartKind::Anchored)
.build(EXTENSIONS)
.expect("Failed to build Aho-Corasick automaton")
});
#[inline(always)]
pub fn match_by_aho_corasick(ext: &str) -> Option<SupportLang> {
if ext.is_empty() {
return None;
}
let ext_lower = ext.to_ascii_lowercase();
for mat in AHO_CORASICK.find_iter(Input::new(&ext_lower).anchored(Anchored::Yes)) {
if mat.end() == ext_lower.len() {
let pattern_id = mat.pattern().as_usize();
return Some(EXTENSION_TO_LANG[pattern_id]);
}
}
None
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_aho_corasick_matching() {
assert_eq!(match_by_aho_corasick("rs"), Some(SupportLang::Rust));
assert_eq!(match_by_aho_corasick("py"), Some(SupportLang::Python));
assert_eq!(match_by_aho_corasick("js"), Some(SupportLang::JavaScript));
assert_eq!(match_by_aho_corasick("RS"), Some(SupportLang::Rust));
assert_eq!(match_by_aho_corasick("PY"), Some(SupportLang::Python));
assert_eq!(match_by_aho_corasick("tsx"), Some(SupportLang::Tsx));
assert_eq!(match_by_aho_corasick("cpp"), Some(SupportLang::Cpp));
assert_eq!(match_by_aho_corasick("workflow"), Some(SupportLang::Hcl));
assert_eq!(match_by_aho_corasick("c"), Some(SupportLang::C));
assert_eq!(match_by_aho_corasick("xyz"), None);
assert_eq!(match_by_aho_corasick(""), None);
}
}