bend 0.1.0

Bend types (Forwarder macro to easily forward errors (auto-implements From trait for error type))
Documentation

use proc_macro::TokenStream;
use quote::quote;
use syn::{parse_macro_input, punctuated::Punctuated};

trait Forwarder {}

#[proc_macro_derive(Forwarder, attributes(forward))]
pub fn forwarder(input_stream: TokenStream) -> TokenStream {
    let input = parse_macro_input!(input_stream as syn::ItemEnum);
    let ident = input.ident.clone();
    let (impl_generics, type_generics, where_clause) = input.generics.split_for_impl().to_owned();

    let mut to_derive_idents = Vec::new();
    let mut to_derive_variants = Vec::new();
    let mut to_derive_args: Vec<Vec<syn::Path>> = Vec::new();

    for variant in input.variants.into_iter() {
        for attr in variant.attrs {
            if attr.path().is_ident("forward") {
                match attr.parse_args_with(
                    Punctuated::<syn::Path, syn::Token!(,)>::parse_terminated
                ) {
                    Ok(args) => {
                        to_derive_args.push(args.into_iter().collect());
                    },
                    Err(_) => {
                        to_derive_args.push(Vec::new());
                    }
                };

                to_derive_idents.push(match variant.fields {
                    syn::Fields::Unnamed(ref fields) => {
                        fields.unnamed.clone().into_iter().next().expect("expected a single field")
                    },
                    _ => panic!("expected tuple fields")
                });
                to_derive_variants.push(variant.ident.clone());
            }
        }
    }

    let gen = quote! {
        #(
            impl #impl_generics From<#to_derive_idents> for #ident #type_generics #where_clause {
                fn from(value: #to_derive_idents) -> #ident #type_generics {
                    Self::#to_derive_variants(value)
                }
            }

            #(
                impl #impl_generics From<#to_derive_args> for #ident #type_generics #where_clause {
                    fn from(value: #to_derive_args) -> #ident #type_generics {
                        Self::#to_derive_variants(value.into())
                    }
                }
            )*
        )*
    };

    gen.into()
}