Skip to main content

spdlog_internal/pattern_parser/
error.rs

1use std::fmt::{self, Display};
2
3use nom::error::Error as NomError;
4
5use super::PatternKind;
6use crate::impossible;
7
8#[derive(Debug, PartialEq)]
9pub enum Error {
10    ConflictName {
11        existing: PatternKind<()>,
12        incoming: PatternKind<()>,
13    },
14    Template(TemplateError),
15    Parse(NomError<String>),
16    Multiple(Vec<Error>),
17    #[cfg(test)]
18    __ForInternalTestsUseOnly(usize),
19}
20
21impl Error {
22    pub fn push_err<T>(result: Result<T>, new: Self) -> Result<T> {
23        match result {
24            Ok(_) => Err(new),
25            Err(Self::Multiple(mut errors)) => {
26                errors.push(new);
27                Err(Self::Multiple(errors))
28            }
29            Err(prev) => Err(Error::Multiple(vec![prev, new])),
30        }
31    }
32
33    pub fn push_result<T, N>(result: Result<T>, new: Result<N>) -> Result<T> {
34        match new {
35            Ok(_) => result,
36            Err(err) => Self::push_err(result, err),
37        }
38    }
39}
40
41impl Display for Error {
42    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
43        match self {
44            Error::ConflictName { existing, incoming } => match (existing, incoming) {
45                (PatternKind::BuiltIn(_), PatternKind::Custom { .. }) => {
46                    write!(
47                        f,
48                        "'{}' is already a built-in pattern, please try another name",
49                        existing.placeholder()
50                    )
51                }
52                (PatternKind::Custom { .. }, PatternKind::Custom { .. }) => {
53                    write!(
54                        f,
55                        "the constructor of custom pattern '{}' is specified more than once",
56                        existing.placeholder()
57                    )
58                }
59                (_, PatternKind::BuiltIn { .. }) => {
60                    impossible!("{}", self)
61                }
62            },
63            Error::Template(err) => {
64                write!(f, "template ill-format: {err}")
65            }
66            Error::Parse(err) => {
67                write!(f, "failed to parse template string: {err}")
68            }
69            Error::Multiple(errs) => {
70                writeln!(f, "{} errors detected:", errs.len())?;
71                for err in errs {
72                    writeln!(f, " - {err}")?;
73                }
74                Ok(())
75            }
76            #[cfg(test)]
77            Error::__ForInternalTestsUseOnly(value) => {
78                write!(f, "{value}")
79            }
80        }
81    }
82}
83
84#[derive(Debug, Eq, PartialEq)]
85pub enum TemplateError {
86    WrongPatternKindReference {
87        is_builtin_as_custom: bool,
88        placeholder: String,
89    },
90    UnknownPatternReference {
91        is_custom: bool,
92        placeholder: String,
93    },
94    MultipleStyleRange,
95}
96
97impl Display for TemplateError {
98    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
99        match self {
100            TemplateError::WrongPatternKindReference {
101                is_builtin_as_custom,
102                placeholder,
103            } => {
104                if *is_builtin_as_custom {
105                    write!(
106                        f,
107                        "'{placeholder}' is a built-in pattern, it cannot be used as a custom pattern. try to replace it with `{{{placeholder}}}`"
108                    )
109                } else {
110                    write!(
111                        f,
112                        "'{placeholder}' is a custom pattern, it cannot be used as a built-in pattern. try to replace it with `{{${placeholder}}}`"
113                    )
114                }
115            }
116            TemplateError::UnknownPatternReference {
117                is_custom,
118                placeholder,
119            } => {
120                if *is_custom {
121                    write!(
122                        f,
123                        "the constructor of custom pattern '{placeholder}' is not specified"
124                    )
125                } else {
126                    write!(f, "no built-in pattern named '{placeholder}'")
127                }
128            }
129            TemplateError::MultipleStyleRange => {
130                write!(f, "multiple style ranges are not currently supported")
131            }
132        }
133    }
134}
135
136pub type Result<T> = std::result::Result<T, Error>;
137
138#[cfg(test)]
139mod tests {
140    use super::*;
141
142    #[test]
143    fn push_err() {
144        macro_rules! make_err {
145            ( $($inputs:tt)+ ) => {
146                Error::__ForInternalTestsUseOnly($($inputs)*)
147            };
148        }
149
150        assert!(matches!(
151            Error::push_err(Ok(()), make_err!(1)),
152            Err(make_err!(1))
153        ));
154
155        assert!(matches!(
156            Error::push_err::<()>(Err(make_err!(1)), make_err!(2)),
157            Err(Error::Multiple(v)) if matches!(v[..], [make_err!(1), make_err!(2)])
158        ));
159    }
160}