use std::fmt::{Display, Formatter, self};
use std::convert::Infallible;
use proc_macro2::Span;
#[derive(Clone, Debug)]
pub enum Error {
Parse(syn::Error),
NamesDontMatch(String, String),
MultipleSingularValues(String),
MultipleLiteralValues(String),
UnsupportedLiteral(String),
SingularAttrRequired(String),
ParametrizedAttrRequired(String),
AttributeUnknownArgument {
attr: String,
arg: String,
},
ArgTypeProhibited {
attr: String,
arg: String,
},
ArgNumberExceedsMax {
attr: String,
type_name: String,
no: usize,
max_no: u8,
},
ArgMustNotHaveValue {
attr: String,
arg: String,
},
ArgRequired {
attr: String,
arg: String,
},
ArgNameMustBeIdent,
ArgNameMustBeUnique {
attr: String,
arg: String,
},
ArgValueRequired {
attr: String,
arg: String,
},
ArgValueTypeMismatch {
attr: String,
arg: String,
},
ArgValueMustBeLiteral,
ArgValueMustBeType,
ParametrizedAttrHasNoValue(String),
NestedListsNotSupported(String),
}
impl From<Infallible> for Error {
fn from(_: Infallible) -> Self {
unreachable!()
}
}
impl From<syn::Error> for Error {
fn from(err: syn::Error) -> Self {
Error::Parse(err)
}
}
impl From<Error> for syn::Error {
fn from(err: Error) -> Self {
syn::Error::new(Span::call_site(), err.to_string())
}
}
impl Display for Error {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
match self {
Error::Parse(err) => write!(f, "attribute parse error: {}", err),
Error::NamesDontMatch(name1, name2) => write!(
f,
"Names of two merged attributes (`{}` and `{}`) must match",
name1,
name2
),
Error::MultipleSingularValues(name) => write!(
f,
"Multiple values assigned to `{}` attribute",
name
),
Error::MultipleLiteralValues(name) => write!(
f,
"Multiple literal values provided for `{}` attribute",
name
),
Error::SingularAttrRequired(name) => write!(
f,
"Attribute `{}` must be in a singular form (`#[attr]` or `#[attr = ...]`)",
name
),
Error::ParametrizedAttrRequired(name) => write!(
f,
"Attribute `{}` must be in a parametrized form (`#[attr(...)]`)",
name
),
Error::ArgMustNotHaveValue { attr, arg } => write!(
f,
"Argument {arg} in `{attr}` attribute must not have a value",
attr = attr, arg = arg
),
Error::ArgTypeProhibited { attr, arg: type_name } => write!(
f,
"Attribute `{}` prohibits arguments of type `{}`",
attr, type_name
),
Error::ArgRequired { attr, arg } => write!(
f,
"Attribute `{}` requires argument `{}` to be explicitly specified",
attr, arg,
),
Error::ArgNameMustBeUnique { attr, arg } => write!(
f,
"Argument names must be unique, while attribute `{}` contains multiple arguments with name`{}`",
attr, arg,
),
Error::ArgNameMustBeIdent => write!(
f,
"Attribute arguments must be identifiers, not paths",
),
Error::ArgValueRequired { attr, arg } => write!(
f,
"Attribute `{}` requires value for argument `{}`",
attr, arg
),
Error::ArgValueMustBeLiteral => f.write_str(
"Attribute argument value must be a literal (string, int etc)",
),
Error::ArgValueMustBeType => {
f.write_str("Attribute value for must be a valid type name")
}
Error::ParametrizedAttrHasNoValue(name) => {
write!(
f,
"Attribute `{name}` must be in a `#[{name} = ...]` form",
name = name
)
}
Error::NestedListsNotSupported(name) => write!(
f,
"Attribute `{name}` must be in `{name} = ...` form and a nested list",
name = name,
),
Error::UnsupportedLiteral(attr) => write!(
f,
"Attribute `{}` has an unsupported type of literal as one of its arguments",
attr
),
Error::AttributeUnknownArgument { attr, arg } => write!(
f,
"Attribute `{}` has an unknown argument `{}`",
attr, arg
),
Error::ArgNumberExceedsMax { attr, type_name, no, max_no } => write!(
f,
"Attribute `{}` has excessive number of arguments of type `{}` ({} while only {} are allowed)",
attr, type_name, no, max_no
),
Error::ArgValueTypeMismatch { attr, arg } => write!(
f,
"Type mismatch in attribute `{}` argument `{}`",
attr, arg
),
}
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Error::Parse(err) => Some(err),
Error::NamesDontMatch(_, _)
| Error::MultipleSingularValues(_)
| Error::MultipleLiteralValues(_)
| Error::SingularAttrRequired(_)
| Error::ArgMustNotHaveValue { .. }
| Error::ArgTypeProhibited { .. }
| Error::ArgRequired { .. }
| Error::ParametrizedAttrRequired(_)
| Error::ArgNameMustBeIdent
| Error::ArgNameMustBeUnique { .. }
| Error::ArgValueRequired { .. }
| Error::ArgValueMustBeLiteral
| Error::ArgValueMustBeType
| Error::ParametrizedAttrHasNoValue(_)
| Error::UnsupportedLiteral(_)
| Error::AttributeUnknownArgument { .. }
| Error::ArgNumberExceedsMax { .. }
| Error::ArgValueTypeMismatch { .. }
| Error::NestedListsNotSupported(_) => None,
}
}
}