use proc_macro2::Span;
use syn::{
Attribute, Error, LitInt, Meta, Token, punctuated::Punctuated,
spanned::Spanned,
};
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
pub enum Repr {
Transparent,
C,
}
impl Repr {
pub fn determine(
attrs: &[Attribute],
bound: &str,
) -> Result<Self, Error> {
let mut repr = None;
for attr in attrs {
if !attr.path().is_ident("repr") {
continue;
}
let nested = attr.parse_args_with(
Punctuated::<Meta, Token![,]>::parse_terminated,
)?;
for meta in nested {
match meta {
Meta::Path(p) if p.is_ident("transparent") => {
repr = Some(Repr::Transparent);
}
Meta::Path(p) if p.is_ident("C") => {
repr = Some(Repr::C);
}
Meta::Path(p) if p.is_ident("Rust") => {
return Err(Error::new_spanned(
p,
format!(
"repr(Rust) is not stable, cannot derive {bound} for it"
),
));
}
Meta::Path(p) if p.is_ident("packed") => {
}
Meta::List(meta)
if meta.path.is_ident("packed")
|| meta.path.is_ident("aligned") =>
{
let span = meta.span();
let lit: LitInt = syn::parse2(meta.tokens)?;
let n: usize = lit.base10_parse()?;
if n != 1 {
return Err(Error::new(
span,
format!(
"'Self' must be unaligned to derive {bound}"
),
));
}
}
meta => {
return Err(Error::new_spanned(
meta,
"unrecognized repr attribute",
));
}
}
}
}
repr.ok_or_else(|| {
Error::new(Span::call_site(),
"repr(C) or repr(transparent) must be specified to derive this")
})
}
}