use proc_macro2::TokenStream;
use proc_macro_error::emit_error;
use syn::parse::{Nothing, Parse};
pub fn consume_attr<T: Parse>(
attrs: &mut Vec<syn::Attribute>,
ident_str: &'static str,
) -> Option<T> {
let mut result = None;
for attr in core::mem::take(attrs) {
if !attr_ident_matches(&attr, ident_str) {
attrs.push(attr);
continue;
}
if result.is_some() {
emit_error!(attr, "duplicate attribute");
}
let tokens = get_attr_tokens(&attr).unwrap_or_default();
match syn::parse2(tokens) {
Ok(value) => result = Some(value),
Err(err) => {
emit_error!(err.span(), "{}", err);
}
}
}
result
}
pub fn consume_flag(attrs: &mut Vec<syn::Attribute>, ident_str: &'static str) -> bool {
consume_attr::<Nothing>(attrs, ident_str).is_some()
}
pub fn check_attr_is_empty(attr: impl Into<TokenStream>) {
let attr = attr.into();
if let Err(err) = syn::parse2::<Nothing>(attr) {
emit_error!(err.span(), "{}", err);
}
}
fn attr_ident_matches(attr: &syn::Attribute, value: &'static str) -> bool {
matches!(attr.path().get_ident(), Some(ident) if *ident == value)
}
fn get_attr_tokens(attr: &syn::Attribute) -> Option<TokenStream> {
if let syn::Meta::List(syn::MetaList { tokens, .. }) = &attr.meta {
Some(tokens.clone())
} else {
None
}
}