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};
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()?,
})
}
}
#[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 => {
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
}
}