nesting 0.1.1

Nesting structs, enums, and impls, in Rust!
Documentation
use super::*;

pub struct EnumDef {
    pub attrs: Vec<Attribute>,
    pub vis: Visibility,
    pub name: Ident,
    pub variants: Vec<VariantDef>,
    pub nested_items: Vec<ItemDef>,
}

impl Parse for EnumDef {
    fn parse(input: ParseStream) -> Result<Self> {
        let attrs = input.call(Attribute::parse_outer)?;
        let vis = input.parse::<Visibility>()?;
        input.parse::<Token![enum]>()?;

        let name = input.parse::<Ident>()?;

        let content;
        syn::braced!(content in input);

        let mut variants: Vec<VariantDef> = Vec::new();
        let mut nested_items: Vec<ItemDef> = Vec::new();

        while !content.is_empty() {
            let is_nested_item = {
                let lookahead = content.fork();
                lookahead.call(Attribute::parse_outer).is_ok()
                    && lookahead.parse::<Visibility>().is_ok()
                    && lookahead.parse::<Option<Token![async]>>().is_ok()
                    && (lookahead.peek(Token![struct])
                        || lookahead.peek(Token![enum])
                        || lookahead.peek(Token![impl])
                        || lookahead.peek(Token![fn]))
            };

            if is_nested_item {
                let mut result = content.parse()?;

                match &mut result {
                    ItemDef::LooseFunc { func: _, parent } => {
                        *parent = Some(name.clone());
                    }
                    _ => {}
                }

                nested_items.push(result);

                // Optional trailing comma
                if content.peek(Token![,]) {
                    content.parse::<Token![,]>()?;
                }
                continue;
            }

            let attrs = content.call(Attribute::parse_outer)?;
            let name = content.parse::<Ident>()?;

            // Tuple variant
            if content.peek(syn::token::Paren) {
                let inner;
                syn::parenthesized!(inner in content);

                let mut fields = Vec::new();
                while !inner.is_empty() {
                    let attrs = inner.call(Attribute::parse_outer)?;
                    let vis = inner.parse::<Visibility>()?;
                    let ty = inner.parse::<Type>()?;

                    let name = Ident::new(&format!("_{}", fields.len()), ty.span());

                    fields.push(FieldDef {
                        attrs,
                        vis,
                        ty,
                        name,
                    });

                    // Optional trailing comma
                    if inner.peek(Token![,]) {
                        inner.parse::<Token![,]>()?;
                    }
                }

                variants.push(VariantDef::Tuple(TupleVariant {
                    attrs,
                    name,
                    fields,
                }));

                // Optional trailing comma
                if content.peek(Token![,]) {
                    content.parse::<Token![,]>()?;
                }

                continue;
            }

            // Struct variant
            if content.peek(syn::token::Brace) {
                let inner;
                syn::braced!(inner in content);

                let mut fields = Vec::new();
                while !inner.is_empty() {
                    let attrs = inner.call(Attribute::parse_outer)?;
                    let vis = inner.parse::<Visibility>()?;
                    let name = inner.parse::<Ident>()?;
                    inner.parse::<Token![:]>()?;
                    let ty = inner.parse::<Type>()?;

                    fields.push(FieldDef {
                        attrs,
                        vis,
                        name,
                        ty,
                    });

                    // Optional trailing comma
                    if inner.peek(Token![,]) {
                        inner.parse::<Token![,]>()?;
                    }
                }

                variants.push(VariantDef::Struct(StructVariant {
                    attrs,
                    name,
                    fields,
                }));

                // Optional trailing comma
                if content.peek(Token![,]) {
                    content.parse::<Token![,]>()?;
                }

                continue;
            }

            // Unit variant
            variants.push(VariantDef::Unit(UnitVariant { attrs, name }));

            // Optional trailing comma
            if content.peek(Token![,]) {
                content.parse::<Token![,]>()?;
            }
        }

        // Optional trailing comma
        if content.peek(Token![,]) {
            content.parse::<Token![,]>()?;
        }

        Ok(EnumDef {
            attrs,
            name,
            nested_items,
            vis,
            variants,
        })
    }
}

pub enum VariantDef {
    Unit(UnitVariant),
    Tuple(TupleVariant),
    Struct(StructVariant),
}

pub struct UnitVariant {
    pub attrs: Vec<Attribute>,
    pub name: Ident,
}

pub struct TupleVariant {
    pub attrs: Vec<Attribute>,
    pub name: Ident,
    pub fields: Vec<FieldDef>,
}

pub struct StructVariant {
    pub attrs: Vec<Attribute>,
    pub name: Ident,
    pub fields: Vec<FieldDef>,
}