grep_regex/
error.rs

1/// An error that can occur in this crate.
2///
3/// Generally, this error corresponds to problems building a regular
4/// expression, whether it's in parsing, compilation or a problem with
5/// guaranteeing a configured optimization.
6#[derive(Clone, Debug)]
7pub struct Error {
8    kind: ErrorKind,
9}
10
11impl Error {
12    pub(crate) fn new(kind: ErrorKind) -> Error {
13        Error { kind }
14    }
15
16    pub(crate) fn regex(err: regex_automata::meta::BuildError) -> Error {
17        if let Some(size_limit) = err.size_limit() {
18            let kind = ErrorKind::Regex(format!(
19                "compiled regex exceeds size limit of {size_limit}",
20            ));
21            Error { kind }
22        } else if let Some(ref err) = err.syntax_error() {
23            Error::generic(err)
24        } else {
25            Error::generic(err)
26        }
27    }
28
29    pub(crate) fn generic<E: std::error::Error>(err: E) -> Error {
30        Error { kind: ErrorKind::Regex(err.to_string()) }
31    }
32
33    /// Return the kind of this error.
34    pub fn kind(&self) -> &ErrorKind {
35        &self.kind
36    }
37}
38
39/// The kind of an error that can occur.
40#[derive(Clone, Debug)]
41#[non_exhaustive]
42pub enum ErrorKind {
43    /// An error that occurred as a result of parsing a regular expression.
44    /// This can be a syntax error or an error that results from attempting to
45    /// compile a regular expression that is too big.
46    ///
47    /// The string here is the underlying error converted to a string.
48    Regex(String),
49    /// An error that occurs when a building a regex that isn't permitted to
50    /// match a line terminator. In general, building the regex will do its
51    /// best to make matching a line terminator impossible (e.g., by removing
52    /// `\n` from the `\s` character class), but if the regex contains a
53    /// `\n` literal, then there is no reasonable choice that can be made and
54    /// therefore an error is reported.
55    ///
56    /// The string is the literal sequence found in the regex that is not
57    /// allowed.
58    NotAllowed(String),
59    /// This error occurs when a non-ASCII line terminator was provided.
60    ///
61    /// The invalid byte is included in this error.
62    InvalidLineTerminator(u8),
63    /// Occurs when a banned byte was found in a pattern.
64    Banned(u8),
65}
66
67impl std::error::Error for Error {}
68
69impl std::fmt::Display for Error {
70    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
71        use bstr::ByteSlice;
72
73        match self.kind {
74            ErrorKind::Regex(ref s) => write!(f, "{}", s),
75            ErrorKind::NotAllowed(ref lit) => {
76                write!(f, "the literal {:?} is not allowed in a regex", lit)
77            }
78            ErrorKind::InvalidLineTerminator(byte) => {
79                write!(
80                    f,
81                    "line terminators must be ASCII, but {byte:?} is not",
82                    byte = [byte].as_bstr(),
83                )
84            }
85            ErrorKind::Banned(byte) => {
86                write!(
87                    f,
88                    "pattern contains {byte:?} but it is impossible to match",
89                    byte = [byte].as_bstr(),
90                )
91            }
92        }
93    }
94}