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                        "'{placeholder}' is a built-in pattern, it cannot be used as a custom pattern. try to replace it with `{{{placeholder}}}`"
109                    )
110                } else {
111                    write!(
112                        f,
113                        "'{placeholder}' is a custom pattern, it cannot be used as a built-in pattern. try to replace it with `{{${placeholder}}}`"
114                    )
115                }
116            }
117            TemplateError::UnknownPatternReference {
118                is_custom,
119                placeholder,
120            } => {
121                if *is_custom {
122                    write!(
123                        f,
124                        "the constructor of custom pattern '{placeholder}' is not specified"
125                    )
126                } else {
127                    write!(f, "no built-in pattern named '{placeholder}'")
128                }
129            }
130            TemplateError::MultipleStyleRange => {
131                write!(f, "multiple style ranges are not currently supported")
132            }
133        }
134    }
135}
136
137pub type Result<T> = std::result::Result<T, Error>;
138
139#[cfg(test)]
140mod tests {
141    use super::*;
142
143    #[test]
144    fn push_err() {
145        macro_rules! make_err {
146            ( $($inputs:tt)+ ) => {
147                Error::__ForInternalTestsUseOnly($($inputs)*)
148            };
149        }
150
151        assert!(matches!(
152            Error::push_err(Ok(()), make_err!(1)),
153            Err(make_err!(1))
154        ));
155
156        assert!(matches!(
157            Error::push_err::<()>(Err(make_err!(1)), make_err!(2)),
158            Err(Error::Multiple(v)) if matches!(v[..], [make_err!(1), make_err!(2)])
159        ));
160    }
161}