@@ -25,19 +25,13 @@ pub fn display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
25
25
continue ;
26
26
}
27
27
28
- if variant_properties. transparent . is_some ( ) {
29
- let arm_end = match & variant. fields {
30
- Fields :: Unnamed ( f) if f. unnamed . len ( ) == 1 => {
31
- quote ! { ( ref v) => :: core:: fmt:: Display :: fmt( v, f) }
32
- }
33
- Fields :: Named ( f) if f. named . len ( ) == 1 => {
34
- let ident = f. named . last ( ) . unwrap ( ) . ident . as_ref ( ) . unwrap ( ) ;
35
- quote ! { { ref #ident} => :: core:: fmt:: Display :: fmt( #ident, f) }
36
- }
37
- _ => return Err ( non_single_field_variant_error ( "transparent" ) ) ,
38
- } ;
28
+ if let Some ( ..) = variant_properties. transparent {
29
+ let arm = super :: extract_single_field_variant_and_then ( name, variant, |tok| {
30
+ quote ! { :: core:: fmt:: Display :: fmt( #tok, f) }
31
+ } )
32
+ . map_err ( |_| non_single_field_variant_error ( "transparent" ) ) ?;
39
33
40
- arms. push ( quote ! { #name :: #ident #arm_end } ) ;
34
+ arms. push ( arm ) ;
41
35
continue ;
42
36
}
43
37
@@ -55,7 +49,8 @@ pub fn display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
55
49
. enumerate ( )
56
50
. map ( |( index, field) | {
57
51
assert ! ( field. ident. is_none( ) ) ;
58
- let ident = syn:: parse_str :: < Ident > ( format ! ( "field{}" , index) . as_str ( ) ) . unwrap ( ) ;
52
+ let ident =
53
+ syn:: parse_str :: < Ident > ( format ! ( "field{}" , index) . as_str ( ) ) . unwrap ( ) ;
59
54
quote ! { ref #ident }
60
55
} )
61
56
. collect ( ) ;
@@ -77,86 +72,87 @@ pub fn display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
77
72
} ;
78
73
79
74
if variant_properties. to_string . is_none ( ) && variant_properties. default . is_some ( ) {
80
- match & variant. fields {
81
- Fields :: Unnamed ( fields) if fields. unnamed . len ( ) == 1 => {
82
- arms. push ( quote ! { #name:: #ident( ref s) => :: core:: fmt:: Display :: fmt( s, f) } ) ;
75
+ let arm = super :: extract_single_field_variant_and_then ( name, variant, |tok| {
76
+ quote ! { :: core:: fmt:: Display :: fmt( #tok, f) }
77
+ } )
78
+ . map_err ( |_| {
79
+ syn:: Error :: new_spanned (
80
+ variant,
81
+ "Default only works on newtype structs with a single String field" ,
82
+ )
83
+ } ) ?;
84
+
85
+ arms. push ( arm) ;
86
+ continue ;
87
+ }
88
+
89
+ let arm = match variant. fields {
90
+ Fields :: Named ( ref field_names) => {
91
+ let used_vars = capture_format_string_idents ( & output) ?;
92
+ if used_vars. is_empty ( ) {
93
+ quote ! { #name:: #ident #params => :: core:: fmt:: Display :: fmt( #output, f) }
94
+ } else {
95
+ // Create args like 'name = name, age = age' for format macro
96
+ let args: Punctuated < _ , Token ! ( , ) > = field_names
97
+ . named
98
+ . iter ( )
99
+ . filter_map ( |field| {
100
+ let ident = field. ident . as_ref ( ) . unwrap ( ) ;
101
+ // Only contain variables that are used in format string
102
+ if !used_vars. contains ( ident) {
103
+ None
104
+ } else {
105
+ Some ( quote ! { #ident = #ident } )
106
+ }
107
+ } )
108
+ . collect ( ) ;
109
+
110
+ quote ! {
111
+ #[ allow( unused_variables) ]
112
+ #name:: #ident #params => :: core:: fmt:: Display :: fmt( & format_args!( #output, #args) , f)
113
+ }
83
114
}
84
- _ => {
115
+ }
116
+ Fields :: Unnamed ( ref unnamed_fields) => {
117
+ let used_vars = capture_format_strings ( & output) ?;
118
+ if used_vars. iter ( ) . any ( String :: is_empty) {
85
119
return Err ( syn:: Error :: new_spanned (
86
- variant ,
87
- "Default only works on newtype structs with a single String field " ,
88
- ) )
120
+ & output ,
121
+ "Empty {} is not allowed; Use manual numbering ({0}) " ,
122
+ ) ) ;
89
123
}
90
- }
91
- } else {
92
- let arm = match variant. fields {
93
- Fields :: Named ( ref field_names) => {
94
- let used_vars = capture_format_string_idents ( & output) ?;
95
- if used_vars. is_empty ( ) {
96
- quote ! { #name:: #ident #params => :: core:: fmt:: Display :: fmt( #output, f) }
97
- } else {
98
- // Create args like 'name = name, age = age' for format macro
99
- let args: Punctuated < _ , Token ! ( , ) > = field_names
100
- . named
101
- . iter ( )
102
- . filter_map ( |field| {
103
- let ident = field. ident . as_ref ( ) . unwrap ( ) ;
104
- // Only contain variables that are used in format string
105
- if !used_vars. contains ( ident) {
106
- None
107
- } else {
108
- Some ( quote ! { #ident = #ident } )
109
- }
110
- } )
111
- . collect ( ) ;
112
-
113
- quote ! {
114
- #[ allow( unused_variables) ]
115
- #name:: #ident #params => :: core:: fmt:: Display :: fmt( & format_args!( #output, #args) , f)
116
- }
117
- }
118
- } ,
119
- Fields :: Unnamed ( ref unnamed_fields) => {
120
- let used_vars = capture_format_strings ( & output) ?;
121
- if used_vars. iter ( ) . any ( String :: is_empty) {
122
- return Err ( syn:: Error :: new_spanned (
123
- & output,
124
- "Empty {} is not allowed; Use manual numbering ({0})" ,
125
- ) )
126
- }
127
- if used_vars. is_empty ( ) {
128
- quote ! { #name:: #ident #params => :: core:: fmt:: Display :: fmt( #output, f) }
129
- } else {
130
- let args: Punctuated < _ , Token ! ( , ) > = unnamed_fields
131
- . unnamed
132
- . iter ( )
133
- . enumerate ( )
134
- . map ( |( index, field) | {
135
- assert ! ( field. ident. is_none( ) ) ;
136
- syn:: parse_str :: < Ident > ( format ! ( "field{}" , index) . as_str ( ) ) . unwrap ( )
137
- } )
138
- . collect ( ) ;
139
- quote ! {
140
- #[ allow( unused_variables) ]
141
- #name:: #ident #params => :: core:: fmt:: Display :: fmt( & format!( #output, #args) , f)
142
- }
124
+ if used_vars. is_empty ( ) {
125
+ quote ! { #name:: #ident #params => :: core:: fmt:: Display :: fmt( #output, f) }
126
+ } else {
127
+ let args: Punctuated < _ , Token ! ( , ) > = unnamed_fields
128
+ . unnamed
129
+ . iter ( )
130
+ . enumerate ( )
131
+ . map ( |( index, field) | {
132
+ assert ! ( field. ident. is_none( ) ) ;
133
+ syn:: parse_str :: < Ident > ( format ! ( "field{}" , index) . as_str ( ) ) . unwrap ( )
134
+ } )
135
+ . collect ( ) ;
136
+ quote ! {
137
+ #[ allow( unused_variables) ]
138
+ #name:: #ident #params => :: core:: fmt:: Display :: fmt( & format!( #output, #args) , f)
143
139
}
144
140
}
145
- Fields :: Unit => {
146
- let used_vars = capture_format_strings ( & output) ?;
147
- if !used_vars. is_empty ( ) {
148
- return Err ( syn:: Error :: new_spanned (
149
- & output,
150
- "Unit variants do not support interpolation" ,
151
- ) ) ;
152
- }
153
-
154
- quote ! { #name:: #ident #params => :: core:: fmt:: Display :: fmt( #output, f) }
141
+ }
142
+ Fields :: Unit => {
143
+ let used_vars = capture_format_strings ( & output) ?;
144
+ if !used_vars. is_empty ( ) {
145
+ return Err ( syn:: Error :: new_spanned (
146
+ & output,
147
+ "Unit variants do not support interpolation" ,
148
+ ) ) ;
155
149
}
156
- } ;
157
150
158
- arms. push ( arm) ;
159
- }
151
+ quote ! { #name:: #ident #params => :: core:: fmt:: Display :: fmt( #output, f) }
152
+ }
153
+ } ;
154
+
155
+ arms. push ( arm) ;
160
156
}
161
157
162
158
if arms. len ( ) < variants. len ( ) {
@@ -175,14 +171,17 @@ pub fn display_inner(ast: &DeriveInput) -> syn::Result<TokenStream> {
175
171
}
176
172
177
173
fn capture_format_string_idents ( string_literal : & LitStr ) -> syn:: Result < Vec < Ident > > {
178
- capture_format_strings ( string_literal) ?. into_iter ( ) . map ( |ident| {
179
- syn:: parse_str :: < Ident > ( ident. as_str ( ) ) . map_err ( |_| {
180
- syn:: Error :: new_spanned (
181
- string_literal,
182
- "Invalid identifier inside format string bracket" ,
183
- )
174
+ capture_format_strings ( string_literal) ?
175
+ . into_iter ( )
176
+ . map ( |ident| {
177
+ syn:: parse_str :: < Ident > ( ident. as_str ( ) ) . map_err ( |_| {
178
+ syn:: Error :: new_spanned (
179
+ string_literal,
180
+ "Invalid identifier inside format string bracket" ,
181
+ )
182
+ } )
184
183
} )
185
- } ) . collect ( )
184
+ . collect ( )
186
185
}
187
186
188
187
fn capture_format_strings ( string_literal : & LitStr ) -> syn:: Result < Vec < String > > {
0 commit comments