structural_derive 0.4.3

Implementation detail of the structural crate.
Documentation
use crate::{
    arenas::Arenas, field_access::Access, ident_or_index::IdentOrIndexRef,
    ignored_wrapper::Ignored, parse_utils::ParseBufferExt,
};

use super::{
    attribute_parsing, FieldType, IdentType, StructuralAlias, StructuralAliases,
    StructuralDataType, StructuralField, StructuralVariant, TinyStructuralField,
};

use as_derive_utils::{datastructure::StructKind, return_syn_err, utils::type_from_ident};

#[allow(unused_imports)]
use core_extensions::{matches, SelfOps};

use syn::{
    parse::{discouraged::Speculative, ParseStream, Parser},
    punctuated::Punctuated,
    token, Attribute, Generics, Ident, Token, TraitItem, Visibility,
};

use std::collections::HashSet;

////////////////////////////////////////////////////////////////////////////////

impl<'a> StructuralAliases<'a> {
    pub(super) fn parse(arenas: &'a Arenas, input: ParseStream<'_>) -> Result<Self, syn::Error> {
        let mut list = Vec::<StructuralAlias<'_>>::new();
        while !input.is_empty() {
            list.push(StructuralAlias::parse(arenas, input)?);
        }
        Ok(Self { list })
    }
}

impl<'a> StructuralAlias<'a> {
    pub(super) fn parse(arenas: &'a Arenas, input: ParseStream<'_>) -> Result<Self, syn::Error> {
        let mut extra_items = Vec::<TraitItem>::new();
        let mut attrs = input.call(Attribute::parse_outer)?;
        let vis: Visibility = input.parse()?;

        let trait_token: Token![trait] = input.parse()?;

        let ident = arenas.alloc(input.parse::<Ident>()?);

        let options = attribute_parsing::parse_attrs(&attrs, ident, arenas)?;

        attrs.retain(|attr| !attr.path.is_ident("struc"));

        let mut generics: Generics = input.parse()?;
        let colon_token: Option<Token![:]> = input.parse()?;

        let mut supertraits = Punctuated::new();
        if colon_token.is_some() {
            loop {
                supertraits.push_value(input.parse()?);
                if input.peek(Token![where]) || input.peek(token::Brace) {
                    break;
                }
                supertraits.push_punct(input.parse()?);
                if input.peek(Token![where]) || input.peek(token::Brace) {
                    break;
                }
            }
        }

        generics.where_clause = input.parse()?;

        // let equal:Token![=]= input.parse()?;

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

        let type_params = generics
            .type_params()
            .map(|tp| &tp.ident)
            .collect::<Vec<&Ident>>();

        let datatype = StructuralDataType::parse(&mut extra_items, &type_params, arenas, &content)?;

        let span = trait_token
            .span
            .join(braces.span)
            .unwrap_or(trait_token.span);

        Ok(Self {
            span,
            attrs,
            vis,
            ident,
            generics,
            supertraits,
            extra_items,
            datatype,
            options,
        })
    }
}

impl<'a> StructuralDataType<'a> {
    pub(super) fn parse(
        extra_items: &mut Vec<TraitItem>,
        type_params: &[&syn::Ident],
        arenas: &'a Arenas,
        input: ParseStream<'_>,
    ) -> Result<Self, syn::Error> {
        let mut variants = Vec::new();
        let mut fields = Vec::new();
        loop {
            if input.is_empty() {
                break;
            }

            let forked = input.fork();
            if let Ok(item) = forked.parse::<TraitItem>() {
                input.advance_to(&forked);
                extra_items.push(item);
                continue;
            }

            let access = input.parse::<Access>()?;
            let ident = IdentType::parse(type_params, arenas, input)?;
            if let Some(enum_token) = VariantToken::peek_from(input) {
                let variant_kind: StructKind = enum_token.into();
                let mut push_variant = |content: ParseStream<'_>| -> Result<(), syn::Error> {
                    variants.push(StructuralVariant::parse(
                        access,
                        ident,
                        variant_kind,
                        type_params,
                        arenas,
                        content,
                    )?);
                    Ok(())
                };

                let content;
                match enum_token {
                    VariantToken::Brace => {
                        let _ = syn::braced!(content in input);
                        push_variant(&content)?;
                    }
                    VariantToken::Paren => {
                        let _ = syn::parenthesized!(content in input);
                        push_variant(&content)?;
                    }
                    VariantToken::NoToken => {
                        Parser::parse_str(push_variant, "")?;
                    }
                }
                if !input.is_empty() {
                    input.parse::<Token![,]>()?;
                }
            } else {
                fields.push(StructuralField::parse_braced_field(
                    access, ident, arenas, input,
                )?);
            }
        }
        {
            let mut set = HashSet::new();
            for variant in &variants {
                if set.replace(variant.name).is_some() {
                    return_syn_err!(
                        variant.name.span(),
                        "Cannot repeat variant name in the same trait declaration"
                    )
                }
            }
        }
        check_no_repeated_field(&fields)?;
        Ok(Self {
            type_name: None,
            variants,
            fields,
        })
    }
}

impl<'a> StructuralVariant<'a> {
    pub(super) fn parse(
        access: Access,
        name: IdentType<'a>,
        variant_kind: StructKind,
        type_params: &[&syn::Ident],
        arenas: &'a Arenas,
        input: ParseStream<'_>,
    ) -> Result<Self, syn::Error> {
        let mut fields = Vec::<StructuralField<'a>>::new();

        match variant_kind {
            StructKind::Braced => {
                while !input.is_empty() {
                    let nested_access = Access::parse_optional(input)?;
                    let ident = IdentType::parse(type_params, arenas, input)?;
                    fields.push(StructuralField::parse_braced_field(
                        nested_access.unwrap_or(access),
                        ident,
                        arenas,
                        input,
                    )?);
                    check_no_repeated_field(&fields)?;
                }
            }
            StructKind::Tuple => {
                let mut index = 0;
                while !input.is_empty() {
                    let nested_access = Access::parse_optional(input)?;
                    fields.push(StructuralField::parse_tuple_field(
                        nested_access.unwrap_or(access),
                        index,
                        arenas,
                        input,
                    )?);
                    index += 1;
                }
            }
        }
        Ok(Self {
            name,
            pub_vari_rename: None,
            fields,
            is_newtype: false,
            replace_bounds: None,
        })
    }
}

impl<'a> TinyStructuralField<'a> {
    pub(crate) fn parse(
        access: Access,
        type_params: &[&syn::Ident],
        arenas: &'a Arenas,
        input: ParseStream<'_>,
    ) -> Result<Self, syn::Error> {
        let ident = IdentType::parse(type_params, arenas, input)?;
        let _: Token![:] = input.parse()?;
        let ty = FieldType::parse(arenas, input)?;

        Ok(Self { access, ident, ty })
    }
}

impl<'a> StructuralField<'a> {
    pub(super) fn parse_braced_field(
        access: Access,
        ident: IdentType<'a>,
        arenas: &'a Arenas,
        input: ParseStream<'_>,
    ) -> Result<Self, syn::Error> {
        let _: Token![:] = input.parse()?;
        let ty = FieldType::parse(arenas, input)?;

        if !input.is_empty() {
            input.parse::<Token![,]>()?;
        }

        Ok(Self {
            access,
            ident,
            pub_field_rename: None,
            ty,
        })
    }

    pub(super) fn parse_tuple_field(
        access: Access,
        index: u32,
        arenas: &'a Arenas,
        input: ParseStream<'_>,
    ) -> Result<Self, syn::Error> {
        let span = input.cursor().span();
        let ty = FieldType::parse(arenas, input)?;
        let ident = IdentOrIndexRef::Index {
            index,
            span: Ignored::new(span),
        }
        .piped(IdentType::Ident);

        if !input.is_empty() {
            input.parse::<Token![,]>()?;
        }

        Ok(Self {
            access,
            ident,
            pub_field_rename: None,
            ty,
        })
    }
}

////////////////////////////////////////////////////////////////////////////////

impl<'a> IdentType<'a> {
    pub(super) fn parse(
        type_params: &[&syn::Ident],
        arenas: &'a Arenas,
        input: ParseStream<'_>,
    ) -> Result<Self, syn::Error> {
        if let Some(_) = input.peek_parse(Token!(<))? {
            let ret = if input.peek(syn::Ident) && input.peek2(Token!(>)) {
                let ident = input.parse::<syn::Ident>()?;
                if type_params.contains(&&ident) {
                    IdentType::Generic(arenas.alloc(ident))
                } else {
                    let ty = type_from_ident(ident);
                    IdentType::SomeType(arenas.alloc(ty))
                }
            } else {
                let ty = input.parse::<syn::Type>()?;
                IdentType::SomeType(arenas.alloc(ty))
            };
            input.parse::<Token!(>)>()?;
            Ok(ret)
        } else {
            IdentOrIndexRef::parse(arenas, input).map(IdentType::Ident)
        }
    }
}

////////////////////////////////////////////////////////////////////////////////

#[derive(Debug, Copy, Clone)]
enum VariantToken {
    Brace,
    Paren,
    NoToken,
}

impl VariantToken {
    pub(super) fn peek_from(input: ParseStream<'_>) -> Option<Self> {
        if input.peek(token::Brace) {
            Some(VariantToken::Brace)
        } else if input.peek(token::Paren) {
            Some(VariantToken::Paren)
        } else if input.peek(token::Comma) || input.is_empty() {
            Some(VariantToken::NoToken)
        } else {
            None
        }
    }
}

impl From<VariantToken> for StructKind {
    fn from(v: VariantToken) -> Self {
        match v {
            VariantToken::Brace => StructKind::Braced,
            _ => StructKind::Tuple,
        }
    }
}

////////////////////////////////////////////////////////////////////////////////

fn check_no_repeated_field(fields: &[StructuralField<'_>]) -> Result<(), syn::Error> {
    let mut set = HashSet::with_capacity(fields.len());
    for field in fields {
        if set.replace(field.ident).is_some() {
            return_syn_err!(field.ident.span(), "Cannot redefine field")
        }
    }
    Ok(())
}

impl<'a> FieldType<'a> {
    pub(super) fn parse(arenas: &'a Arenas, input: ParseStream<'_>) -> Result<Self, syn::Error> {
        const ASSOC_TY_BOUNDS: bool = cfg!(feature = "impl_fields");

        use syn::Type;

        match input.parse::<syn::Type>()? {
            Type::ImplTrait(x) => {
                if ASSOC_TY_BOUNDS {
                    Ok(FieldType::Impl(arenas.alloc(x.bounds)))
                } else {
                    use syn::spanned::Spanned;
                    Err(syn::Error::new(
                        x.span(),
                        "\
                         Cannot use an `impl Trait` field without enabling the \
                         \"nightly_impl_fields\" or \"impl_fields\" feature.\
                         ",
                    ))
                }
            }
            x => Ok(FieldType::Ty(arenas.alloc(x))),
        }
    }
}