#![allow(deprecated)]
use std::convert::Infallible;
use std::fmt::{self, Display, Formatter};
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,
ArgValueMustBeExpr,
ParametrizedAttrHasNoValue(String),
#[deprecated(
since = "1.1.0",
note = "This error variant is not used anymore after the introduction of custom attribute \
parser"
)]
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::ArgValueMustBeExpr => {
f.write_str("Attribute value for must be a valid expression")
}
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::ArgValueMustBeExpr |
Error::ParametrizedAttrHasNoValue(_) |
Error::UnsupportedLiteral(_) |
Error::AttributeUnknownArgument { .. } |
Error::ArgNumberExceedsMax { .. } |
Error::ArgValueTypeMismatch { .. } => None,
Error::NestedListsNotSupported(_) => None,
}
}
}