faf_replay_parser_derive/
lib.rs1use proc_macro::TokenStream;
2use quote::quote;
3use syn;
4
5mod attr;
6mod parse;
7
8#[proc_macro_derive(Display, attributes(display))]
9pub fn display_derive(input: TokenStream) -> TokenStream {
10 let ast = syn::parse_macro_input!(input as syn::DeriveInput);
11
12 impl_display_derive(&ast)
13}
14
15fn impl_display_derive(ast: &syn::DeriveInput) -> TokenStream {
16 let name = &ast.ident;
17
18 let body = impl_body(name, &ast.data);
19
20 let gen = quote! {
21 impl ::core::fmt::Display for #name {
22 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
23 use crate::display::DisplayBuilders;
24
25 #body
26 }
27 }
28 };
29 gen.into()
30}
31
32fn impl_body(name: &syn::Ident, data: &syn::Data) -> proc_macro2::TokenStream {
33 use syn::{Data, Fields};
34
35 match *data {
36 Data::Struct(ref data) => match data.fields {
37 Fields::Named(ref fields) => {
38 let names = fields
39 .named
40 .iter()
41 .map(|field| field.ident.as_ref().unwrap());
42 let field_calls = fields.named.iter().map(|field| {
43 let (name, display) = get_field_display(field);
44 quote! {
45 .field(#name, #display)
46 }
47 });
48 quote! {
49 match *self {
50 #name { #(ref #names),* } => {
51 f.display_struct()
52 .name(stringify!(#name))
53 #(#field_calls)*
54 .finish()
55 }
56 }
57 }
58 }
59 Fields::Unnamed(ref _fields) => {
60 quote!(Ok(()))
61 }
62 Fields::Unit => {
63 quote!(Ok(()))
64 }
65 },
66 Data::Enum(ref data) => {
67 let arms = data.variants.iter().map(|var| {
68 let params = attr::VariantParams::from_attrs(&var.attrs);
69 let variant_name = &var.ident;
70
71 match var.fields {
72 Fields::Named(ref fields) => {
73 let names = fields
74 .named
75 .iter()
76 .map(|field| field.ident.as_ref().unwrap());
77 let field_calls = fields.named.iter().map(|field| {
78 let (name, display) = get_field_display(field);
79 quote! {
80 .field(#name, #display)
81 }
82 });
83 quote! {
84 #variant_name { #(ref #names),* } => {
85 f.display_struct()
86 .name(stringify!(#variant_name))
87 #(#field_calls)*
88 .finish()
89 }
90 }
91 }
92 Fields::Unnamed(ref _fields) => {
93 if params.transparent {
94 quote! {
95 #variant_name(ref inner) => ::core::fmt::Display::fmt(&inner, f)
96 }
97 } else {
98 quote! {
99 #variant_name(ref inner) => write!(f, concat!(stringify!(#variant_name), "({})"), inner)
100 }
101 }
102 }
103 Fields::Unit => quote! {
104 #variant_name => {
105 f.display_struct()
106 .name(stringify!(#variant_name))
107 .finish()
108 }
109 },
110 }
111 });
112 quote! {
113 match *self {
114 #(#name::#arms),*
115 }
116 }
117 }
118 Data::Union(_) => unimplemented!(),
119 }
120}
121
122fn get_field_display(field: &syn::Field) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
123 let params = attr::FieldParams::from_attrs(&field.attrs);
124 let field_name = field.ident.as_ref().unwrap();
125
126 let name = match params.name {
127 Some(ref name) => quote!(#name),
128 None => quote!(stringify!(#field_name)),
129 };
130
131 let value = params
132 .fmt_with
133 .as_ref()
134 .map(|fmt_with| quote!(&#fmt_with(#field_name)))
135 .unwrap_or_else(|| match params.debug {
136 true => quote!(&crate::display::DisplayAsDebug(#field_name)),
137 false => quote!(#field_name),
138 });
139
140 (name, value)
141}