use core::fmt::{self, Display, Formatter};
use proc_macro2::Span;
use syn::{spanned::Spanned, Ident, Path, Variant};
use crate::{common::path::path_to_string, Trait};
struct DisplayStringSlice<'a>(&'a [&'static str]);
impl<'a> Display for DisplayStringSlice<'a> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
if !self.0.is_empty() {
f.write_str(", which should be reformatted as follows:")?;
for &s in self.0 {
f.write_str("\n ")?;
f.write_str(s)?;
}
}
Ok(())
}
}
struct DisplayTraits;
impl Display for DisplayTraits {
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
for t in &Trait::VARIANTS[..Trait::VARIANTS.len() - 1] {
f.write_str("\n ")?;
f.write_fmt(format_args!("{t:?}"))?;
}
Ok(())
}
}
#[inline]
pub(crate) fn derive_attribute_not_set_up_yet() -> syn::Error {
syn::Error::new(
Span::call_site(),
"you are using `Educe` in the `derive` attribute, but it has not been set up yet",
)
}
#[inline]
pub(crate) fn attribute_incorrect_place(name: &Ident) -> syn::Error {
syn::Error::new(name.span(), format!("the `{name}` attribute cannot be placed here"))
}
#[inline]
pub(crate) fn attribute_incorrect_format_with_span(
name: &Ident,
span: Span,
correct_usage: &[&'static str],
) -> syn::Error {
if correct_usage.is_empty() {
attribute_incorrect_place(name)
} else {
syn::Error::new(
span,
format!(
"you are using an incorrect format of the `{name}` attribute{}",
DisplayStringSlice(correct_usage)
),
)
}
}
#[inline]
pub(crate) fn attribute_incorrect_format(
name: &Ident,
correct_usage: &[&'static str],
) -> syn::Error {
attribute_incorrect_format_with_span(name, name.span(), correct_usage)
}
#[inline]
pub(crate) fn parameter_reset(name: &Ident) -> syn::Error {
syn::Error::new(name.span(), format!("you are trying to reset the `{name}` parameter"))
}
#[inline]
pub(crate) fn educe_format_incorrect(name: &Ident) -> syn::Error {
attribute_incorrect_format(name, &[stringify!(#[educe(Trait1, Trait2, ..., TraitN)])])
}
#[inline]
pub(crate) fn unsupported_trait(name: &Path) -> syn::Error {
let span = name.span();
match name.get_ident() {
Some(name) => syn::Error::new(
span,
format!("unsupported trait `{name}`, available traits:{DisplayTraits}"),
),
None => {
let name = path_to_string(name);
syn::Error::new(
span,
format!("unsupported trait `{name}`, available traits:{DisplayTraits}"),
)
},
}
}
#[inline]
pub(crate) fn reuse_a_trait(name: &Ident) -> syn::Error {
syn::Error::new(name.span(), format!("the trait `{name}` is used repeatedly"))
}
#[inline]
pub(crate) fn trait_not_used(name: &Ident) -> syn::Error {
syn::Error::new(name.span(), format!("the trait `{name}` is not used"))
}
#[inline]
pub(crate) fn trait_not_support_union(name: &Ident) -> syn::Error {
syn::Error::new(name.span(), format!("the trait `{name}` does not support to a union"))
}
#[inline]
pub(crate) fn trait_not_support_unit_variant(name: &Ident, variant: &Variant) -> syn::Error {
syn::Error::new(
variant.span(),
format!("the trait `{name}` cannot be implemented for an enum which has unit variants"),
)
}