trident_derive_displayix/
lib.rs

1use proc_macro::TokenStream;
2use quote::quote;
3use syn::{parse_macro_input, Data, DeriveInput};
4
5#[proc_macro_derive(DisplayIx)]
6pub fn display_ix(input: TokenStream) -> TokenStream {
7    let input = parse_macro_input!(input as DeriveInput);
8    let enum_name = &input.ident;
9
10    let display_impl = match &input.data {
11        Data::Enum(enum_data) => {
12            let to_context_string_match_arms = enum_data.variants.iter().map(|variant| {
13                let variant_name = &variant.ident;
14                quote! {
15                    #enum_name::#variant_name (_) => String::from(stringify!(#variant_name)),
16                }
17            });
18            let display_match_arms = enum_data.variants.iter().map(|variant| {
19                let variant_name = &variant.ident;
20
21                match &variant.fields {
22                    syn::Fields::Unnamed(fields) => {
23                        if fields.unnamed.len() == 1 {
24                            quote! {
25                                #enum_name::#variant_name(ref content) => {
26                                    write!(f, stringify!(#variant_name))?;
27                                    write!(f, "({:#?})", content)
28                                },
29                            }
30                        } else {
31                            quote! {
32                                #enum_name::#variant_name (_) => write!(f, stringify!(#variant_name)),
33                            }
34                        }
35                    },
36                    _ => quote! {
37                        #enum_name::#variant_name => write!(f, stringify!(#variant_name)),
38                    },
39                }
40            });
41
42            quote! {
43                impl std::fmt::Display for #enum_name {
44                    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45                        match self {
46                            #(#display_match_arms)*
47                        }
48                    }
49                }
50                impl #enum_name {
51                    fn to_context_string(&self)->String{
52                        match self {
53                            #(#to_context_string_match_arms)*
54                        }
55                    }
56                }
57            }
58        }
59        _ => panic!("DisplayIx can only be derived for enums"),
60    };
61
62    TokenStream::from(display_impl)
63}