structural_derive 0.4.3

Implementation detail of the structural crate.
Documentation
use crate::{
    arenas::Arenas,
    datastructure::StructOrEnum,
    parse_utils::ParseBufferExt,
    structural_alias_impl_mod::{TinyStructuralField, TypeParamBounds},
};

use proc_macro2::TokenStream as TokenStream2;

use quote::{quote, ToTokens, TokenStreamExt};

use syn::parse::{discouraged::Speculative, Parse, ParseStream};

pub(crate) fn impl_(data: ImplStructHack) -> Result<TokenStream2, syn::Error> {
    Ok(data.tokens)
}

pub(crate) struct ImplStructHack {
    pub(crate) tokens: TokenStream2,
}

pub(crate) struct ImplStruct<'a> {
    bounds: TypeParamBounds,
    fields: Vec<TinyStructuralField<'a>>,
}

impl<'a> Parse for ImplStructHack {
    fn parse(input: ParseStream<'_>) -> Result<Self, syn::Error> {
        let arenas = Arenas::default();

        let impl_struct = ImplStruct::parse(&arenas, input)?;
        Ok(ImplStructHack {
            tokens: impl_struct.into_token_stream(),
        })
    }
}

impl<'a> ImplStruct<'a> {
    fn parse(arenas: &'a Arenas, input: ParseStream<'_>) -> Result<Self, syn::Error> {
        let forked = input.fork();
        let mut bounds = TypeParamBounds::parse_separated_nonempty_with(&forked, Parse::parse).ok();
        let _ = forked.peek_parse(syn::Token!(+));
        let sep = forked.parse::<syn::Token!(;)>();
        if sep.is_ok() {
            input.advance_to(&forked);
        } else {
            bounds = None;
        }

        let mut fields = Vec::new();

        while !input.is_empty() {
            let access = input.parse()?;
            fields.push(TinyStructuralField::parse(access, &[], &arenas, input)?);
            input.peek_parse(syn::Token![,])?;
        }

        let bounds = bounds.unwrap_or_default();
        Ok(ImplStruct { bounds, fields })
    }
}

impl<'a> ToTokens for ImplStruct<'a> {
    fn to_tokens(&self, tokens: &mut TokenStream2) {
        let bounds = self.bounds.iter();
        let fields = self.fields.iter().map(|f| f.tokens(StructOrEnum::Struct));
        tokens.append_all(quote!(
            impl #( #bounds+ )* #( #fields+ )*
        ));
    }
}