axum-err-handler-macro 0.2.1

A macro implementation for AxumErrorHandler
Documentation
use crate::ParseStream;
use quote::quote;
use syn::Fields;
use syn::{Attribute, LitStr};

pub fn parse_general_response_context(
    name: &syn::Ident,
    variant: &syn::Variant,
) -> proc_macro2::TokenStream {
    let ident = &variant.ident;

    let status_code = variant
        .attrs
        .iter()
        .find_map(|attr| parse_status_code(attr))
        .unwrap_or(quote! { 500 });
    let code = variant
        .attrs
        .iter()
        .find_map(|attr| parse_code_string(attr))
        .unwrap_or_else(|| ident.to_string());

    let pattern = match &variant.fields {
        Fields::Named(_) => {
            panic!("Named fields are not supported in enum variants for response parsing")
        }
        Fields::Unit => quote! { #name::#ident },
        Fields::Unnamed(_) => {
            quote! { #name::#ident(..) }
        }
    };

    let body = match &variant.fields {
        Fields::Unit => quote! { format!("{}", self) },
        Fields::Named(_) => {
            panic!("Named fields are not supported in enum variants for response parsing")
        }
        Fields::Unnamed(_) => {
            quote! { self.to_string() }
        }
    };

    quote! {
        #pattern => {
            axum_error_handler::ErrorResponseContext::builder()
                .status_code(#status_code)
                .code(#code.to_string())
                .message(#body)
                .build()
        }
    }
}

fn parse_status_code(attr: &Attribute) -> Option<proc_macro2::TokenStream> {
    if attr.path().is_ident("status_code") {
        let result = attr.parse_args_with(|input: ParseStream| {
            let fmt: LitStr = input.parse()?;

            let val = fmt.value();

            Ok(quote! { #val.parse().unwrap_or(500) })
        });

        if result.is_err() {
            println!("Error parsing status code");
            return Some(quote! { 500 });
        }

        Some(result.unwrap())
    } else {
        None
    }
}

fn parse_code_string(attr: &Attribute) -> Option<String> {
    if attr.path().is_ident("code") {
        let result = attr.parse_args_with(|input: ParseStream| {
            let fmt: LitStr = input.parse().unwrap();

            Ok(fmt.value())
        });

        if result.is_err() {
            return Some("".to_string());
        }

        Some(result.unwrap())
    } else {
        None
    }
}