enum-status-code-macros 0.1.0

Macros for enum-status-code
Documentation
extern crate proc_macro;
use itertools::Itertools;
use manyhow::manyhow;
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data::Enum, DeriveInput, Error, Expr, parse2, spanned::Spanned};

#[manyhow(proc_macro_derive(StatusCode))]
pub fn derive_status_code(input: TokenStream) -> syn::Result<TokenStream> {
    let input: DeriveInput = parse2(input)?;
    let enum_name = &input.ident;
    let enum_span = input.span();
    let default = input
        .attrs
        .iter()
        .find_map(|attr| {
            if attr.path().is_ident("derive") {
                match attr.parse_args::<Expr>() {
                    Ok(attr) => match attr {
                        Expr::Path(path) => path.path.is_ident("StatusCode").then_some(Ok(None)),
                        Expr::Call(call) => {
                            if let Expr::Path(path) = *call.func {
                                path.path.is_ident("StatusCode").then_some(Ok(call
                                    .args
                                    .first()
                                    .cloned()
                                    .map(Ok)))
                            } else {
                                None
                            }
                        }
                        _ => Some(Err(Error::new(attr.span(), "invalid attribute arguments"))),
                    },
                    Err(error) => Some(Err(error)),
                }
            } else {
                None
            }
        })
        .ok_or(Error::new(enum_span, "missing derive macro"))??;

    if let Enum(data) = input.data {
        data.variants
            .iter()
            .map(|variant| {
                if let Some(value) = variant
                    .attrs
                    .iter()
                    .find_map(|attr| {
                        attr.path()
                            .is_ident("status_code")
                            .then_some(attr.parse_args::<Expr>())
                    })
                    .or(default.clone())
                {
                    let value = value?;
                    Ok(quote! {
                        #enum_name::#variant.ident => #value
                    })
                } else {
                    Err(Error::new(variant.span(), "variant is missing status_code"))
                }
            })
            .process_results(|iter| {
                iter.tree_reduce(|a, b| {
                    quote! {
                        #a
                        #b
                    }
                })
            })?
            .map(|contents| {
                quote! {
                    impl enum_status_code::StatusCode for #enum_name {
                        fn status_code(&self) -> enum_status_code::http::StatusCode {
                            match self {
                                #contents
                            }
                        }
                    }
                }
            })
            .ok_or(Error::new(enum_span, "expcted enum body"))
    } else {
        Err(Error::new(enum_span, "expected enum"))
    }
}