use crate::{hybrid::id::LazyStateIDError, nfa}; /// An error that occurs when initial construction of a lazy DFA fails. /// /// A build error can occur when insufficient cache capacity is configured or /// if something about the NFA is unsupported. (For example, if one attempts /// to build a lazy DFA without heuristic Unicode support but with an NFA that /// contains a Unicode word boundary.) /// /// This error does not provide many introspection capabilities. There are /// generally only two things you can do with it: /// /// * Obtain a human readable message via its `std::fmt::Display` impl. /// * Access an underlying /// [`nfa::thompson::BuildError`](crate::nfa::thompson::BuildError) /// type from its `source` method via the `std::error::Error` trait. This error /// only occurs when using convenience routines for building a lazy DFA /// directly from a pattern string. /// /// When the `std` feature is enabled, this implements the `std::error::Error` /// trait. #[derive(Clone, Debug)] pub struct BuildError { kind: BuildErrorKind, } #[derive(Clone, Debug)] enum BuildErrorKind { NFA(nfa::thompson::BuildError), InsufficientCacheCapacity { minimum: usize, given: usize }, InsufficientStateIDCapacity { err: LazyStateIDError }, Unsupported(&'static str), } impl BuildError { pub(crate) fn nfa(err: nfa::thompson::BuildError) -> BuildError { BuildError { kind: BuildErrorKind::NFA(err) } } pub(crate) fn insufficient_cache_capacity( minimum: usize, given: usize, ) -> BuildError { BuildError { kind: BuildErrorKind::InsufficientCacheCapacity { minimum, given }, } } pub(crate) fn insufficient_state_id_capacity( err: LazyStateIDError, ) -> BuildError { BuildError { kind: BuildErrorKind::InsufficientStateIDCapacity { err }, } } pub(crate) fn unsupported_dfa_word_boundary_unicode() -> BuildError { let msg = "cannot build lazy DFAs for regexes with Unicode word \ boundaries; switch to ASCII word boundaries, or \ heuristically enable Unicode word boundaries or use a \ different regex engine"; BuildError { kind: BuildErrorKind::Unsupported(msg) } } } #[cfg(feature = "std")] impl std::error::Error for BuildError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { match self.kind { BuildErrorKind::NFA(ref err) => Some(err), _ => None, } } } impl core::fmt::Display for BuildError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { match self.kind { BuildErrorKind::NFA(_) => write!(f, "error building NFA"), BuildErrorKind::InsufficientCacheCapacity { minimum, given } => { write!( f, "given cache capacity ({}) is smaller than \ minimum required ({})", given, minimum, ) } BuildErrorKind::InsufficientStateIDCapacity { ref err } => { err.fmt(f) } BuildErrorKind::Unsupported(ref msg) => { write!(f, "unsupported regex feature for DFAs: {}", msg) } } } } /// An error that occurs when cache usage has become inefficient. /// /// One of the weaknesses of a lazy DFA is that it may need to clear its /// cache repeatedly if it's not big enough. If this happens too much, then it /// can slow searching down significantly. A mitigation to this is to use /// heuristics to detect whether the cache is being used efficiently or not. /// If not, then a lazy DFA can return a `CacheError`. /// /// The default configuration of a lazy DFA in this crate is /// set such that a `CacheError` will never occur. Instead, /// callers must opt into this behavior with settings like /// [`dfa::Config::minimum_cache_clear_count`](crate::hybrid::dfa::Config::minimum_cache_clear_count) /// and /// [`dfa::Config::minimum_bytes_per_state`](crate::hybrid::dfa::Config::minimum_bytes_per_state). /// /// When the `std` feature is enabled, this implements the `std::error::Error` /// trait. #[derive(Clone, Debug)] pub struct CacheError(()); impl CacheError { pub(crate) fn too_many_cache_clears() -> CacheError { CacheError(()) } pub(crate) fn bad_efficiency() -> CacheError { CacheError(()) } } #[cfg(feature = "std")] impl std::error::Error for CacheError { fn source(&self) -> Option<&(dyn std::error::Error + 'static)> { None } } impl core::fmt::Display for CacheError { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "lazy DFA cache has been cleared too many times") } }