spdlog_internal/pattern_parser/
error.rs

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