atruct 0.3.2

macros for anonymous structs in Rust
Documentation
use proc_macro2::{Ident, Span, Punct};
use syn::{
    punctuated::Punctuated,
    token::{Comma, Colon, Brace, At, Paren, Bang, Sub},
    parse::{Parse, ParseStream},
    braced, Expr, Type, parenthesized, Error
};


pub struct Atruct {
    fields: Punctuated<Field, Comma>,
}
#[derive(Clone)]
pub struct Field {
    pub name:            Ident,
    pub type_annotation: Option<TypeAnnotation>,
    _colon:              Colon,
    pub content:         FieldContent,
}
#[derive(Clone)]
pub enum TypeAnnotation {
    AtAnnotation {
        _at:           At,
        type_of_value: Type,
    },
    ParenAnnotation {
        _paren:        Paren,
        type_of_valle: Type,
    },
}
#[derive(Clone)]
pub enum FieldContent {
    Value {
        prefix: Option<Prefix>,
        expr:   Expr,
    },
    Nest {
        _brace: Brace,
        fields: Punctuated<Field, Comma>,
    },
}
#[derive(Clone)]
pub enum Prefix {
    Bang,
    Minus,
}


impl Atruct {
    pub fn into_fields(self) -> Punctuated<Field, Comma> {
        self.fields
    }
} impl Parse for Atruct {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(Atruct {
            fields: input.parse_terminated(Field::parse)?
        })
    }
} impl Parse for Field {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        Ok(Field {
            name: input.parse().expect("expected identifier / not supporting block value like `field: {let v = Vec::new(); v}`"),
            type_annotation:
                if input.peek(At)
                || input.peek(Paren) {
                    Some(input.parse()?)
                } else {None},
            _colon:  input.parse()?,
            content: input.parse()?,
        })
    }
} impl Parse for TypeAnnotation {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        if input.peek(At) {
            Ok(Self::AtAnnotation {
                _at:           input.parse()?,
                type_of_value: input.parse()?,
            })
        } else if input.peek(Paren) {
            let type_buf;
            Ok(Self::ParenAnnotation {
                _paren:        parenthesized!(type_buf in input),
                type_of_valle: type_buf.parse()?,
            })
        } else {
            Err(Error::new(Span::call_site(), "unexpected type annotation"))
        }
    }
} impl Parse for FieldContent {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let fields_buf;
        if input.peek(Brace) {
            Ok(Self::Nest {
                _brace: braced!(fields_buf in input),
                fields: fields_buf.parse_terminated(Field::parse)?,
            })
        } else {
            Ok(Self::Value {
                prefix:
                    if input.peek(Bang) {
                        input.parse::<Punct>().unwrap();
                        Some(Prefix::Bang)
                    } else if input.peek(Sub) {
                        input.parse::<Punct>().unwrap();
                        Some(Prefix::Minus)
                    } else {None},
                expr: input.parse()?
            })
        }
    }
}