use quote::{ToTokens, quote};
use syn::spanned::Spanned;
pub enum ItemFnStructEnum<'a> {
Fn(&'a mut syn::ItemFn),
Struct(&'a mut syn::ItemStruct),
Enum(&'a mut syn::ItemEnum),
}
impl ItemFnStructEnum<'_> {
pub fn ident(&self) -> &syn::Ident {
match self {
Self::Fn(i) => &i.sig.ident,
Self::Struct(i) => &i.ident,
Self::Enum(i) => &i.ident,
}
}
pub fn attrs(&self) -> &Vec<syn::Attribute> {
match self {
Self::Fn(i) => &i.attrs,
Self::Struct(i) => &i.attrs,
Self::Enum(i) => &i.attrs,
}
}
pub fn attrs_mut(&mut self) -> &mut Vec<syn::Attribute> {
match self {
Self::Fn(i) => &mut i.attrs,
Self::Struct(i) => &mut i.attrs,
Self::Enum(i) => &mut i.attrs,
}
}
pub fn clone_attrs(&self) -> Vec<syn::Attribute> {
self.attrs().clone()
}
pub fn take_attrs(&mut self) -> Vec<syn::Attribute> {
std::mem::take(self.attrs_mut())
}
pub fn put_attrs(&mut self, attrs: Vec<syn::Attribute>) -> Vec<syn::Attribute> {
std::mem::replace(self.attrs_mut(), attrs)
}
}
impl<'a> TryFrom<&'a mut syn::Item> for ItemFnStructEnum<'a> {
type Error = syn::Error;
fn try_from(value: &'a mut syn::Item) -> Result<Self, Self::Error> {
match value {
syn::Item::Fn(i) => Ok(Self::Fn(i)),
syn::Item::Struct(i) => Ok(Self::Struct(i)),
syn::Item::Enum(i) => Ok(Self::Enum(i)),
other => Err(syn::Error::new(
other.span(),
"expected a function, struct, or enum",
)),
}
}
}
impl ToTokens for ItemFnStructEnum<'_> {
fn to_tokens(&self, tokens: &mut proc_macro2::TokenStream) {
tokens.extend(match self {
Self::Fn(i) => quote! { #i },
Self::Struct(i) => quote! { #i },
Self::Enum(i) => quote! { #i },
});
}
}
#[allow(dead_code)]
pub trait ItemExt {
fn ident(&self) -> Option<&syn::Ident>;
}
impl ItemExt for syn::Item {
fn ident(&self) -> Option<&syn::Ident> {
Some(match self {
syn::Item::Const(i) => &i.ident,
syn::Item::Enum(i) => &i.ident,
syn::Item::ExternCrate(i) => &i.ident,
syn::Item::Fn(i) => &i.sig.ident,
syn::Item::Macro(i) => return i.ident.as_ref(),
syn::Item::Mod(i) => &i.ident,
syn::Item::Static(i) => &i.ident,
syn::Item::Struct(i) => &i.ident,
syn::Item::Trait(i) => &i.ident,
syn::Item::TraitAlias(i) => &i.ident,
syn::Item::Type(i) => &i.ident,
syn::Item::Union(i) => &i.ident,
_ => return None,
})
}
}
#[allow(dead_code)]
pub trait ItemAttrsExt {
fn attrs_mut(&mut self) -> Option<&mut Vec<syn::Attribute>>;
fn take_attrs(&mut self) -> Option<Vec<syn::Attribute>>;
fn put_attrs(&mut self, attrs: Vec<syn::Attribute>) -> Option<Vec<syn::Attribute>>;
}
impl ItemAttrsExt for syn::Item {
fn attrs_mut(&mut self) -> Option<&mut Vec<syn::Attribute>> {
Some(match self {
syn::Item::Const(i) => &mut i.attrs,
syn::Item::Enum(i) => &mut i.attrs,
syn::Item::ExternCrate(i) => &mut i.attrs,
syn::Item::Fn(i) => &mut i.attrs,
syn::Item::ForeignMod(i) => &mut i.attrs,
syn::Item::Impl(i) => &mut i.attrs,
syn::Item::Macro(i) => &mut i.attrs,
syn::Item::Mod(i) => &mut i.attrs,
syn::Item::Static(i) => &mut i.attrs,
syn::Item::Struct(i) => &mut i.attrs,
syn::Item::Trait(i) => &mut i.attrs,
syn::Item::TraitAlias(i) => &mut i.attrs,
syn::Item::Type(i) => &mut i.attrs,
syn::Item::Union(i) => &mut i.attrs,
syn::Item::Use(i) => &mut i.attrs,
syn::Item::Verbatim(_) => return None,
_ => return None,
})
}
fn take_attrs(&mut self) -> Option<Vec<syn::Attribute>> {
Some(std::mem::take(self.attrs_mut()?))
}
fn put_attrs(&mut self, attrs: Vec<syn::Attribute>) -> Option<Vec<syn::Attribute>> {
Some(std::mem::replace(self.attrs_mut()?, attrs))
}
}