1use darling::{ast, FromDeriveInput, FromField, FromVariant};
2use proc_macro2::TokenStream;
3use quote::{quote, ToTokens};
4
5#[proc_macro_derive(HttpError, attributes(http))]
6pub fn parser(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
7 let ast = syn::parse_macro_input!(input);
8 let gen = BaseReceiver::from_derive_input(&ast).unwrap();
9
10 quote!(#gen).into()
11}
12
13#[derive(Debug, FromDeriveInput)]
14#[darling(attributes(http), supports(enum_any))]
15struct BaseReceiver {
16 ident: syn::Ident,
17 generics: syn::Generics,
18 data: ast::Data<FieldReceiver, ()>,
19}
20
21impl ToTokens for BaseReceiver {
22 fn to_tokens(&self, tokens: &mut TokenStream) {
23 let BaseReceiver {
24 ref ident,
25 ref generics,
26 ref data,
27 } = *self;
28
29 let (imp, ty, wher) = generics.split_for_impl();
30 let fields = data.as_ref().take_enum().expect("Should never be enum");
31 let mut code_tokens = Vec::<TokenStream>::new();
32 let mut message_tokens = Vec::<TokenStream>::new();
33 let mut error_tokens = Vec::<TokenStream>::new();
34
35 fields.into_iter().for_each(|f| {
36 let field_ident = &f.ident;
37
38 let field_variant = match &f.fields.style {
39 ast::Style::Tuple => {
40 quote! { (_) }
41 }
42 ast::Style::Struct => {
43 quote! { { .. } }
44 }
45 _ => quote! {},
46 };
47
48 if let Some(code) = f.code {
49 code_tokens.push(quote! {
50 Self::#field_ident #field_variant => Some(#code),
51 });
52 }
53
54 if let Some(error) = f.error {
55 error_tokens.push(quote! {
56 Self::#field_ident #field_variant => Some(#error),
57 });
58 }
59
60 if f.message.is_some() {
61 let message = f.message.clone().unwrap();
62
63 message_tokens.push(quote! {
64 Self::#field_ident #field_variant => Some(#message),
65 })
66 }
67 });
68
69 tokens.extend(quote! {
70 impl #imp #ident #ty #wher {
71 pub fn http_code(&self) -> Option<u16> {
72 match &self {
73 #(#code_tokens)*
74 _ => None
75 }
76 }
77 pub fn http_message(&self) -> Option<&'static str> {
78 match &self {
79 #(#message_tokens)*
80 _ => None
81 }
82 }
83 pub fn http_error(&self) -> Option<u16> {
84 match &self {
85 #(#error_tokens)*
86 _ => None
87 }
88 }
89 }
90 })
91 }
92}
93
94#[derive(Debug, FromVariant)]
95#[darling(attributes(http))]
96struct FieldReceiver {
97 ident: syn::Ident,
98 fields: ast::Fields<FieldFieldReceiver>,
99 code: Option<u16>,
100 message: Option<String>,
101 error: Option<u16>,
102}
103
104#[derive(Debug, FromField)]
105struct FieldFieldReceiver {}