actix_response_macro/
lib.rs1use std::collections::HashMap;
2
3use proc_macro2::TokenStream;
4use quote::quote;
5use syn::{Ident, ItemEnum};
6
7#[proc_macro_derive(ResponseError, attributes(response_code))]
8pub fn derive_response_error(item: proc_macro::TokenStream) -> proc_macro::TokenStream {
9 let item: TokenStream = item.into();
10 let item: ItemEnum = syn::parse2(item).unwrap();
11 let name = item.ident;
12 let mut variants: Vec<(Ident, Ident)> = Vec::new();
13 for variant in item.variants {
14 let Some(attr) = variant
15 .attrs
16 .iter()
17 .find(|a| a.path().is_ident("response_code"))
18 else {
19 panic!("missing response_code for variant {}", variant.ident);
20 };
21
22 let code: Ident = attr.parse_args().unwrap();
23 variants.push((variant.ident, code));
24 }
25
26 let matches = variants
27 .iter()
28 .map(|(k, v)| {
29 quote! {
30 Self::#k => ::actix_web::http::StatusCode::#v
31 }
32 })
33 .collect::<Vec<_>>();
34
35 let res = quote! {
36 impl ::actix_web::ResponseError for #name {
37 fn error_response(&self) -> ::actix_web::HttpResponse {
38 let status = match self {
39 #(#matches),*
40 };
41
42 ::actix_web::HttpResponse::build(status).json(::actix_response::ApiResponse::<()>::Error(self.to_string()))
43 }
44 }
45 };
46
47 eprintln!("{}", res.to_string());
48
49 res.into()
50}