cgp-macro-lib 0.7.0

Context-generic programming core component macros implemented as a library.
Documentation
use proc_macro2::TokenStream;
use quote::ToTokens;
use syn::parse::{Parse, ParseStream};
use syn::punctuated::Punctuated;
use syn::token::{At, Colon, Comma, Override, Plus, Pound};
use syn::{Error, Ident, braced, bracketed, parenthesized};

use crate::parse::{DelegateEntry, SimpleType, TypeSpec};

pub struct DefinePreset {
    pub provider_wrapper: Option<Ident>,
    pub preset: TypeSpec,
    pub parent_presets: Punctuated<PresetParent, Plus>,
    pub delegate_entries: Punctuated<DelegatePresetEntry, Comma>,
}

pub struct DelegatePresetEntry {
    pub is_override: Option<Override>,
    pub entry: DelegateEntry<SimpleType>,
}

impl Parse for DefinePreset {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let provider_wrapper: Option<Ident> = if input.peek(Pound) {
            let _: Pound = input.parse()?;

            let body;
            bracketed!(body in input);

            let meta: Ident = body.parse()?;
            if meta != "wrap_provider" {
                return Err(Error::new(
                    meta.span(),
                    format!("unsupported attribute: {meta}"),
                ));
            }

            let body2;
            parenthesized!(body2 in body);

            Some(body2.parse()?)
        } else {
            None
        };

        let PresetHead {
            preset,
            parent_presets,
        } = input.parse()?;

        let delegate_entries = {
            let inner;
            braced!(inner in input);
            Punctuated::parse_terminated(&inner)?
        };

        Ok(Self {
            provider_wrapper,
            preset,
            parent_presets,
            delegate_entries,
        })
    }
}

impl Parse for DelegatePresetEntry {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let is_override = if input.peek(Override) {
            let is_override = input.parse()?;
            Some(is_override)
        } else {
            None
        };

        let entry = input.parse()?;

        Ok(Self { is_override, entry })
    }
}

#[derive(Clone)]
pub struct PresetParent {
    pub has_expanded: Option<At>,
    pub parent_type: SimpleType,
}

impl Parse for PresetParent {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let has_expanded = input.parse()?;
        let parent_type = input.parse()?;

        Ok(Self {
            has_expanded,
            parent_type,
        })
    }
}

impl ToTokens for DelegatePresetEntry {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        self.is_override.to_tokens(tokens);
        self.entry.to_tokens(tokens);
    }
}

impl ToTokens for PresetParent {
    fn to_tokens(&self, tokens: &mut TokenStream) {
        self.has_expanded.to_tokens(tokens);
        self.parent_type.to_tokens(tokens);
    }
}

pub struct PresetHead {
    pub preset: TypeSpec,
    pub parent_presets: Punctuated<PresetParent, Plus>,
}

impl Parse for PresetHead {
    fn parse(input: ParseStream) -> syn::Result<Self> {
        let preset = input.parse()?;

        let parent_presets = if input.peek(Colon) {
            let _: Colon = input.parse()?;
            Punctuated::parse_separated_nonempty(input)?
        } else {
            Default::default()
        };

        Ok(Self {
            preset,
            parent_presets,
        })
    }
}