1+ use darling:: FromMeta ;
12use itertools:: Itertools ;
23use proc_macro2:: TokenStream ;
34use quote:: quote;
45use syn:: spanned:: Spanned ;
5- use syn:: { parse_str, Fields , Ident , Lit , Meta , NestedMeta , Path , Result } ;
6+ use syn:: { parse_str, Fields , Ident , Lit , Meta , Path , Result } ;
67use synstructure:: { decl_derive, AddBounds , BindingInfo , Structure , VariantInfo } ;
78
9+ use crate :: field_attributes:: { DebugFormat , FieldAttributes } ;
810use crate :: filter_ext:: RetainExt ;
911use crate :: macros:: { bail, error} ;
1012use crate :: result_into_stream_ext:: ResultIntoStreamExt ;
1113
14+ mod field_attributes;
1215mod filter_ext;
1316mod macros;
1417mod result_into_stream_ext;
@@ -37,24 +40,10 @@ fn custom_debug_derive(mut structure: Structure) -> Result<TokenStream> {
3740}
3841
3942fn filter_out_skipped_fields ( structure : & mut Structure ) -> Result < ( ) > {
40- let skip_ident: Ident = parse_str ( "skip" ) . unwrap ( ) ;
41-
4243 structure. try_retain ( |binding| {
43- for meta in get_custom_debug_metas ( binding) {
44- let meta = meta?;
45-
46- if let NestedMeta :: Meta ( Meta :: Path ( ref path) ) = meta {
47- if path
48- . get_ident ( )
49- . map ( |ident| ident == & skip_ident)
50- . unwrap_or ( false )
51- {
52- return Ok ( false ) ;
53- }
54- }
55- }
44+ let field_attributes = parse_field_attributes ( binding) ?;
5645
57- Ok ( true )
46+ Ok ( !field_attributes . skip )
5847 } ) ?;
5948
6049 Ok ( ( ) )
@@ -82,20 +71,8 @@ fn generate_match_arm_body(variant: &VariantInfo) -> Result<TokenStream> {
8271}
8372
8473fn generate_debug_builder_call ( binding : & BindingInfo ) -> Result < TokenStream > {
85- let mut format = None ;
86-
87- for meta in get_custom_debug_metas ( binding) {
88- let meta = meta?;
89-
90- match meta {
91- NestedMeta :: Meta ( Meta :: NameValue ( nv) ) => {
92- format = Some ( generate_name_value_builder_call ( binding, nv) ?)
93- }
94- _ => bail ! ( meta. span( ) , "Unsupported attribute" ) ,
95- }
96- }
97-
98- let format = format. unwrap_or_else ( || quote ! { #binding } ) ;
74+ let field_attributes = parse_field_attributes ( binding) ?;
75+ let format = generate_debug_impl ( binding, & field_attributes. debug_format ) ;
9976
10077 let debug_builder_call =
10178 if let Some ( ref name) = binding. ast ( ) . ident . as_ref ( ) . map ( <_ >:: to_string) {
@@ -111,70 +88,44 @@ fn generate_debug_builder_call(binding: &BindingInfo) -> Result<TokenStream> {
11188 Ok ( debug_builder_call)
11289}
11390
114- fn generate_name_value_builder_call (
115- binding : & BindingInfo ,
116- nv : syn:: MetaNameValue ,
117- ) -> Result < TokenStream > {
118- let key_span = nv. path . span ( ) ;
119- let value_span = nv. lit . span ( ) ;
120- let value = nv. lit ;
121- let ident = nv
122- . path
123- . get_ident ( )
124- . map ( Ident :: to_string)
125- . ok_or_else ( || error ! ( key_span, "Unsupported attribute" ) ) ?;
126-
127- match & * ident {
128- "format" => Ok ( quote ! { & format_args!( #value, #binding) } ) ,
129- "with" => match value {
130- Lit :: Str ( fun) => {
131- let fun = fun
132- . parse :: < Path > ( )
133- . map_err ( |_| error ! ( fun. span( ) , "Invalid path to function" ) ) ?;
134-
135- Ok ( quote ! {
136- {
137- struct DebugWith <' a, T : ' a> {
138- data: & ' a T ,
139- fmt: fn ( & T , & mut :: core:: fmt:: Formatter ) -> :: core:: fmt:: Result ,
140- }
141-
142- impl <' a, T : ' a> :: core:: fmt:: Debug for DebugWith <' a, T > {
143- fn fmt( & self , fmt: & mut :: core:: fmt:: Formatter ) -> :: core:: fmt:: Result {
144- ( self . fmt) ( self . data, fmt)
145- }
146- }
147-
148- & DebugWith {
149- data: #binding,
150- fmt: #fun,
151- }
91+ fn generate_debug_impl ( binding : & BindingInfo , debug_format : & DebugFormat ) -> TokenStream {
92+ match debug_format {
93+ DebugFormat :: Default => quote ! { #binding } ,
94+ DebugFormat :: Format ( format) => quote ! { & format_args!( #format, #binding) } ,
95+ DebugFormat :: With ( with) => quote ! {
96+ {
97+ struct DebugWith <' a, T : ' a> {
98+ data: & ' a T ,
99+ fmt: fn ( & T , & mut :: core:: fmt:: Formatter ) -> :: core:: fmt:: Result ,
100+ }
101+
102+ impl <' a, T : ' a> :: core:: fmt:: Debug for DebugWith <' a, T > {
103+ fn fmt( & self , fmt: & mut :: core:: fmt:: Formatter ) -> :: core:: fmt:: Result {
104+ ( self . fmt) ( self . data, fmt)
152105 }
153- } )
106+ }
107+
108+ & DebugWith {
109+ data: #binding,
110+ fmt: #with,
111+ }
154112 }
155- _ => bail ! ( value_span, "Invalid `with` value" ) ,
156113 } ,
157- _ => bail ! ( key_span, "Unsupported attribute" ) ,
158114 }
159115}
160116
161- fn get_custom_debug_metas < ' a > (
162- binding : & BindingInfo < ' a > ,
163- ) -> impl Iterator < Item = Result < NestedMeta > > + ' a {
164- let debug_attr = parse_str :: < Path > ( "debug" ) . unwrap ( ) ;
117+ fn parse_field_attributes ( binding : & BindingInfo < ' _ > ) -> Result < FieldAttributes > {
118+ let mut combined_field_attributes = FieldAttributes :: default ( ) ;
165119
166- binding
167- . ast ( )
168- . attrs
169- . iter ( )
170- . filter ( move |attr| attr. path == debug_attr)
171- . map ( |attr| {
172- let meta = attr. parse_meta ( ) ?;
120+ for attr in & binding. ast ( ) . attrs {
121+ if !attr. path ( ) . is_ident ( "debug" ) {
122+ continue ;
123+ }
173124
174- match meta {
175- Meta :: List ( list ) => Ok ( list . nested ) ,
176- _ => bail ! ( meta . span ( ) , "Unsupported attribute style, use `debug(…)`" ) ,
177- }
178- } )
179- . flatten_ok ( )
125+ let field_attributes = FieldAttributes :: from_meta ( & attr . meta ) ? ;
126+
127+ combined_field_attributes = combined_field_attributes . try_combine ( field_attributes ) ? ;
128+ }
129+
130+ Ok ( combined_field_attributes )
180131}
0 commit comments