1extern crate proc_macro;
2
3use proc_macro2::{Ident, Span};
4use quote::quote;
5use syn::{ItemEnum, parse_macro_input, TypePath};
6use proc_macro::TokenStream;
7
8#[proc_macro_derive(Display, attributes(ignore_field, to_vec))]
10pub fn enum_display_derive(input: TokenStream) -> TokenStream {
11 let input = parse_macro_input!(input as ItemEnum);
12 impl_display(input)
13}
14
15#[derive(Default)]
16struct Vars {
17 vars: Vec<proc_macro2::TokenStream>,
18 enum_type: EnumType,
19}
20
21#[derive(Default, PartialEq)]
22enum EnumType {
23 #[default]
24 None,
25 Tuple,
26 Struct,
27}
28
29fn impl_display(input: ItemEnum) -> TokenStream {
30 let name = &input.ident;
31 let mut tokens:Vec<proc_macro2::TokenStream> = vec![];
32 let mut global_ignore_field = false;
33 for attr in &input.attrs {
34 if attr.path().is_ident("ignore_field") {
35 global_ignore_field = true;
36 }
37 }
38 for variant in input.variants {
39 let mut vars = Vars::default();
40 let mut ignore_field = false;
41 for attr in variant.attrs {
42 if attr.path().is_ident("ignore_field") {
43 ignore_field = true;
44 break;
45 }
46 }
47 for (idx,field) in variant.fields.iter().enumerate() {
48 if let syn::Type::Path(TypePath{ path,.. }) = &field.ty {
49 if let Some(ident) = &field.ident {
50 vars.enum_type = EnumType::Struct;
51 for _seg in path.segments.iter() {
52 eprintln!("111:{}", field.ident.clone().unwrap().to_string());
53 vars.vars.push(quote! { #ident });
54 }
55 } else {
56 for _seg in path.segments.iter() {
57 eprintln!("111:");
58 vars.enum_type = EnumType::Tuple;
59 let data = Ident::new(format!("val{}", idx).as_str(), Span::call_site());
60 vars.vars.push(quote! { #data });
61 }
62 }
63 }
64 }
65 let ident = variant.ident;
66 if vars.vars.len() > 0 {
67 let fields = &vars.vars;
68 let fields = quote! { #(#fields),*};
69 if global_ignore_field || ignore_field{
70 if vars.enum_type == EnumType::Tuple {
71 tokens.push(quote! {
72 Self::#ident(#fields) => write!(f, "{}", stringify!(#ident))
73 })
74 } else if vars.enum_type == EnumType::Struct {
75 tokens.push(quote! {
76 Self::#ident{#fields} => write!(f, "{}", stringify!(#ident))
77 })
78 }
79 } else {
80 if vars.enum_type == EnumType::Tuple {
81 tokens.push(quote! {
82 Self::#ident(#fields) => write!(f, "{}:{:?}", stringify!(#ident), (#fields))
83 })
84 } else if vars.enum_type == EnumType::Struct {
85 tokens.push(quote! {
86 Self::#ident{#fields} => write!(f, "{}:{:?}", stringify!(#ident), (#fields))
87 })
88 }
89 }
90 } else {
91 tokens.push(quote! {
92 Self::#ident => write!(f, stringify!(#ident))
93 });
94 }
95 }
96
97 let token = quote! {
98 impl std::fmt::Display for #name {
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 match self {
101 #(#tokens),*
102 }
103 }
104 }
105 };
106 TokenStream::from(token)
107}