use std::fmt::{self, Display};
use nom::error::Error as NomError;
use super::PatternKind;
use crate::impossible;
#[derive(Debug, PartialEq)]
pub enum Error {
ConflictName {
existing: PatternKind<()>,
incoming: PatternKind<()>,
},
Template(TemplateError),
Parse(NomError<String>),
Multiple(Vec<Error>),
#[cfg(test)]
__ForInternalTestsUseOnly(usize),
}
impl Error {
pub fn push_err<T>(result: Result<T>, new: Self) -> Result<T> {
match result {
Ok(_) => Err(new),
Err(Self::Multiple(mut errors)) => {
errors.push(new);
Err(Self::Multiple(errors))
}
Err(prev) => Err(Error::Multiple(vec![prev, new])),
}
}
pub fn push_result<T, N>(result: Result<T>, new: Result<N>) -> Result<T> {
match new {
Ok(_) => result,
Err(err) => Self::push_err(result, err),
}
}
}
impl Display for Error {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Error::ConflictName { existing, incoming } => match (existing, incoming) {
(PatternKind::BuiltIn(_), PatternKind::Custom { .. }) => {
write!(
f,
"'{}' is already a built-in pattern, please try another name",
existing.placeholder()
)
}
(PatternKind::Custom { .. }, PatternKind::Custom { .. }) => {
write!(
f,
"the constructor of custom pattern '{}' is specified more than once",
existing.placeholder()
)
}
(_, PatternKind::BuiltIn { .. }) => {
impossible!("{}", self)
}
},
Error::Template(err) => {
write!(f, "template ill-format: {err}")
}
Error::Parse(err) => {
write!(f, "failed to parse template string: {err}")
}
Error::Multiple(errs) => {
writeln!(f, "{} errors detected:", errs.len())?;
for err in errs {
writeln!(f, " - {err}")?;
}
Ok(())
}
#[cfg(test)]
Error::__ForInternalTestsUseOnly(value) => {
write!(f, "{value}")
}
}
}
}
#[derive(Debug, Eq, PartialEq)]
pub enum TemplateError {
WrongPatternKindReference {
is_builtin_as_custom: bool,
placeholder: String,
},
UnknownPatternReference {
is_custom: bool,
placeholder: String,
},
MultipleStyleRange,
}
impl Display for TemplateError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
TemplateError::WrongPatternKindReference {
is_builtin_as_custom,
placeholder,
} => {
if *is_builtin_as_custom {
write!(
f,
"'{placeholder}' is a built-in pattern, it cannot be used as a custom pattern. try to replace it with `{{{placeholder}}}`"
)
} else {
write!(
f,
"'{placeholder}' is a custom pattern, it cannot be used as a built-in pattern. try to replace it with `{{${placeholder}}}`"
)
}
}
TemplateError::UnknownPatternReference {
is_custom,
placeholder,
} => {
if *is_custom {
write!(
f,
"the constructor of custom pattern '{placeholder}' is not specified"
)
} else {
write!(f, "no built-in pattern named '{placeholder}'")
}
}
TemplateError::MultipleStyleRange => {
write!(f, "multiple style ranges are not currently supported")
}
}
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn push_err() {
macro_rules! make_err {
( $($inputs:tt)+ ) => {
Error::__ForInternalTestsUseOnly($($inputs)*)
};
}
assert!(matches!(
Error::push_err(Ok(()), make_err!(1)),
Err(make_err!(1))
));
assert!(matches!(
Error::push_err::<()>(Err(make_err!(1)), make_err!(2)),
Err(Error::Multiple(v)) if matches!(v[..], [make_err!(1), make_err!(2)])
));
}
}