enum_delegate_lib 0.2.0

Internal macro implementations for enum_delegate - use to implement your own macros
Documentation
use proc_macro2::TokenStream;
use quote::quote;
use syn::parse::{Parse, ParseStream};
use syn::token::Comma;
use syn::{parse2, parse_quote, ItemEnum, ItemTrait, Path};

use crate::generate_delegation::{implement_delegation, DelegationOptions};

/// Parsed input for the `implement` macro.
///
/// A trait path, optionally followed by the trait declaration, separated by a comma
struct TraitArgumentPair {
    path: Path,
    declaration: Option<ItemTrait>,
}

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

        let parse_declaration = || {
            if input.is_empty() {
                return Ok::<_, syn::Error>(None);
            };
            let _: Comma = input.parse()?;
            if input.is_empty() {
                return Ok(None);
            };
            Ok(Some(input.parse()?))
        };

        Ok(TraitArgumentPair {
            path,
            declaration: parse_declaration()?,
        })
    }
}

/// The `implement` macro implementation.
///
/// See the `enum_delegate` crate for more information.
// we're mirroring how macro signatures look
#[allow(clippy::needless_pass_by_value)]
#[must_use]
pub fn implement(attribute_args: TokenStream, item: TokenStream) -> TokenStream {
    let parsed_enum: ItemEnum = match parse2(item.clone()) {
        Ok(parsed) => parsed,
        Err(error) => return error.to_compile_error(),
    };

    let enum_ident = &parsed_enum.ident;
    let enum_path = parse_quote!(#enum_ident);

    let parsed_input: TraitArgumentPair = match parse2(attribute_args) {
        Ok(parsed) => parsed,
        Err(error) => return error.to_compile_error(),
    };

    let delegation = match &parsed_input.declaration {
        None => {
            // the path to the trait, which should also be a macro generated by `register`
            let trait_path = &parsed_input.path;

            quote! {
                #trait_path!(#trait_path, #enum_path, #parsed_enum);
            }
        }
        Some(trait_declaration) => {
            match implement_delegation(
                &parsed_input.path,
                trait_declaration,
                &enum_path,
                &parsed_enum,
                DelegationOptions::default(),
            ) {
                Ok(generated) => generated,
                Err(error) => error.into_compiler_error(),
            }
        }
    };

    quote! {
        #item
        #delegation
    }
}