1use core::fmt;
2use regex_automata::dfa::{sparse::DFA, Automaton};
3use regex_automata::Input;
4use spin::Once;
5
6#[derive(Clone, Copy, Debug, PartialEq, Eq)]
8pub struct Unusable(&'static str);
9
10impl fmt::Display for Unusable {
11 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
12 f.write_str(self.0)
13 }
14}
15
16impl core::error::Error for Unusable {}
17
18pub struct Pattern {
22 bytes: &'static [u8],
23 dfa: Once<Result<DFA<&'static [u8]>, Unusable>>,
24}
25
26impl Pattern {
27 pub const fn new(bytes: &'static [u8]) -> Self {
28 Pattern {
29 bytes,
30 dfa: Once::new(),
31 }
32 }
33
34 pub fn load(&self) -> Result<(), Unusable> {
37 self.dfa().map(|_| ())
38 }
39
40 fn dfa(&self) -> Result<&DFA<&'static [u8]>, Unusable> {
41 self.dfa
42 .call_once(|| {
43 DFA::from_bytes(self.bytes)
44 .map(|(dfa, _)| dfa)
45 .map_err(|_| Unusable("pattern table failed its check"))
46 })
47 .as_ref()
48 .map_err(|e| *e)
49 }
50
51 pub fn is_match(&self, s: &str) -> Result<bool, Unusable> {
56 self.dfa()?
57 .try_search_fwd(&Input::new(s).earliest(true))
58 .map(|m| m.is_some())
59 .map_err(|_| Unusable("pattern search gave up"))
60 }
61}