use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::parse::{Parse, ParseStream};
use syn::{bracketed, token, Meta, Token};
pub enum FieldAttribute {
Nested(NestedAttribute),
Field(Attribute),
}
#[derive(Clone, PartialEq, Eq)]
pub struct Attribute {
pub pound_token: Token![#],
pub bracket_token: token::Bracket,
pub meta: Meta,
}
pub struct NestedAttribute {
pub pound_token: Token![#],
pub ident_token: Token![>],
pub bracket_token: token::Bracket,
pub meta: Meta,
pub modifier: Option<AttributeModifier>,
}
#[derive(Clone)]
pub struct CompositeAttribute {
pub pound_token: Token![#],
pub bracket_token: token::Bracket,
pub meta: Meta,
pub modifier: Option<AttributeModifier>,
}
#[derive(Clone, Copy)]
pub enum AttributeModifier {
Star(Token![*]),
Slash(Token![/]),
Minus(Token![-]),
}
pub trait ParseAttribute: Sized {
fn parse_outer(input: ParseStream) -> syn::Result<Vec<Self>> {
let mut attrs = vec![];
while input.peek(Token![#]) {
attrs.push(input.call(Self::parse_single_outer)?)
}
Ok(attrs)
}
fn parse_single_outer(input: ParseStream) -> syn::Result<Self>;
}
impl Parse for AttributeModifier {
fn parse(input: ParseStream) -> syn::Result<Self> {
let lookahead = input.lookahead1();
if lookahead.peek(Token![*]) {
input.parse().map(Self::Star)
} else if lookahead.peek(Token![/]) {
input.parse().map(Self::Slash)
} else if lookahead.peek(Token![-]) {
input.parse().map(Self::Minus)
} else {
Err(lookahead.error())
}
}
}
impl ParseAttribute for Attribute {
fn parse_single_outer(input: ParseStream) -> syn::Result<Self> {
let content;
Ok(Self {
pound_token: input.parse()?,
bracket_token: bracketed!(content in input),
meta: content.parse()?,
})
}
}
impl ParseAttribute for FieldAttribute {
fn parse_single_outer(input: ParseStream) -> syn::Result<Self> {
if input.peek(Token![#]) && input.peek2(Token![>]) {
Ok(Self::Nested(input.call(NestedAttribute::parse_single_outer)?))
} else {
Ok(Self::Field(input.call(Attribute::parse_single_outer)?))
}
}
}
impl ParseAttribute for NestedAttribute {
fn parse_single_outer(mut input: ParseStream) -> syn::Result<Self> {
let content;
let pound_token = input.parse()?;
let ident_token = input.parse()?;
let bracket_token = bracketed!(content in input);
let meta = content.parse()?;
let modifier = handle_attribute_modifier(&mut input)?;
Ok(Self {
pound_token,
ident_token,
bracket_token,
meta,
modifier,
})
}
}
impl ParseAttribute for CompositeAttribute {
fn parse_single_outer(mut input: ParseStream) -> syn::Result<Self> {
let content;
let pound_token = input.parse()?;
let bracket_token = bracketed!(content in input);
let meta = content.parse()?;
let modifier = handle_attribute_modifier(&mut input)?;
Ok(Self {
pound_token,
bracket_token,
meta,
modifier,
})
}
}
fn handle_attribute_modifier(input: &mut ParseStream) -> syn::Result<Option<AttributeModifier>> {
if input.peek(Token![*])
|| input.peek(Token![/])
|| input.peek(Token![-])
|| input.peek(Token![+])
{
Ok(Some(input.parse()?))
} else {
Ok(None)
}
}
impl ToTokens for Attribute {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.pound_token.to_tokens(tokens);
self.bracket_token
.surround(tokens, |meta_tokens| self.meta.to_tokens(meta_tokens))
}
}
impl ToTokens for CompositeAttribute {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.pound_token.to_tokens(tokens);
self.bracket_token
.surround(tokens, |meta_tokens| self.meta.to_tokens(meta_tokens))
}
}
impl ToTokens for NestedAttribute {
fn to_tokens(&self, tokens: &mut TokenStream) {
self.pound_token.to_tokens(tokens);
self.bracket_token
.surround(tokens, |meta_tokens| self.meta.to_tokens(meta_tokens))
}
}
impl ToTokens for FieldAttribute {
fn to_tokens(&self, tokens: &mut TokenStream) {
match self {
FieldAttribute::Nested(a) => a.to_tokens(tokens),
FieldAttribute::Field(a) => a.to_tokens(tokens),
}
}
}
impl From<NestedAttribute> for Attribute {
fn from(nested: NestedAttribute) -> Self {
Attribute {
pound_token: nested.pound_token,
bracket_token: nested.bracket_token,
meta: nested.meta,
}
}
}
impl From<CompositeAttribute> for Attribute {
fn from(composite: CompositeAttribute) -> Self {
Attribute {
pound_token: composite.pound_token,
bracket_token: composite.bracket_token,
meta: composite.meta,
}
}
}
impl From<NestedAttribute> for CompositeAttribute {
fn from(nested: NestedAttribute) -> Self {
CompositeAttribute {
pound_token: nested.pound_token,
bracket_token: nested.bracket_token,
meta: nested.meta,
modifier: nested.modifier,
}
}
}
impl PartialEq<NestedAttribute> for Attribute {
fn eq(&self, other: &NestedAttribute) -> bool {
self.meta == other.meta
}
}
impl PartialEq<Attribute> for NestedAttribute {
fn eq(&self, other: &Attribute) -> bool {
self.meta == other.meta
}
}
impl PartialEq<CompositeAttribute> for Attribute {
fn eq(&self, other: &CompositeAttribute) -> bool {
self.meta == other.meta
}
}
impl PartialEq<Attribute> for CompositeAttribute {
fn eq(&self, other: &Attribute) -> bool {
self.meta == other.meta
}
}