axum_err_handler_macro/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{DeriveInput, parse::ParseStream, parse_macro_input};
4
5use crate::context::parse_final_response_context_block;
6
7pub(crate) mod context;
8mod custom_fn;
9
10#[proc_macro_derive(AxumErrorResponse, attributes(status_code, code, response))]
11pub fn derive_axum_error_response(input: TokenStream) -> TokenStream {
12    // Parse the input tokens into a syntax tree
13    let input = parse_macro_input!(input as DeriveInput);
14    let custom_fn = custom_fn::parse_custom_fn(&input);
15    let name = input.ident.clone();
16
17    let response_block = parse_final_response_context_block(&name, &input);
18
19    let mut expand = quote! {
20        #response_block
21    };
22
23    if custom_fn.is_some() {
24        let custom_fn_name = custom_fn.unwrap();
25
26        let fn_name = custom_fn_name.value();
27        let fn_ident = syn::Ident::new(&fn_name, custom_fn_name.span());
28
29        expand.extend(quote! {
30            impl axum::response::IntoResponse for #name {
31                fn into_response(self) -> axum::response::Response {
32                    use axum_error_handler::IntoErrorResponseContext;
33
34                    #fn_ident(self.into_response_context())
35                }
36            }
37        });
38
39        TokenStream::from(expand)
40    } else {
41        expand.extend(quote! {
42            impl axum::response::IntoResponse for #name {
43                fn into_response(self) -> axum::response::Response {
44                    use axum_error_handler::IntoErrorResponseContext;
45
46                    self.into_response_context().into_response()
47                }
48            }
49        });
50
51        TokenStream::from(expand)
52    }
53}