@@ -76,7 +76,7 @@ pub fn make_enum_definition_with(
76
76
quote ! { #[ doc( hidden) ] pub }
77
77
} ) ;
78
78
79
- let debug_impl = make_enum_debug_impl ( enum_) ;
79
+ let debug_impl = make_enum_debug_impl ( enum_, define_traits && !enum_ . is_bitfield ) ;
80
80
quote ! {
81
81
#[ repr( transparent) ]
82
82
#[ derive( #( #derives ) , * ) ]
@@ -146,11 +146,8 @@ fn make_enum_index_impl(enum_: &Enum) -> Option<TokenStream> {
146
146
} )
147
147
}
148
148
149
- /// Implement `Debug` trait for the enum.
150
- fn make_enum_debug_impl ( enum_ : & Enum ) -> TokenStream {
151
- let enum_name = & enum_. name ;
152
- let enum_name_str = enum_name. to_string ( ) ;
153
-
149
+ // Creates the match cases to return the enumerator name as &str.
150
+ fn make_enum_to_str_cases ( enum_ : & Enum ) -> TokenStream {
154
151
let enumerators = enum_. enumerators . iter ( ) . map ( |enumerator| {
155
152
let Enumerator { name, .. } = enumerator;
156
153
let name_str = name. to_string ( ) ;
@@ -159,22 +156,55 @@ fn make_enum_debug_impl(enum_: &Enum) -> TokenStream {
159
156
}
160
157
} ) ;
161
158
159
+ quote ! {
160
+ #( #enumerators ) *
161
+ }
162
+ }
163
+
164
+ /// Implement `Debug` trait for the enum.
165
+ fn make_enum_debug_impl ( enum_ : & Enum , use_as_str : bool ) -> TokenStream {
166
+ let enum_name = & enum_. name ;
167
+ let enum_name_str = enum_name. to_string ( ) ;
168
+
169
+ // Print the ord if no matching enumerator can be found.
170
+ let enumerator_not_found = quote ! {
171
+ f. debug_struct( #enum_name_str)
172
+ . field( "ord" , & self . ord)
173
+ . finish( ) ?;
174
+
175
+ return Ok ( ( ) ) ;
176
+ } ;
177
+
178
+ // Reuse `as_str` if traits are defined and not a bitfield.
179
+ let function_body = if use_as_str {
180
+ quote ! {
181
+ use crate :: obj:: EngineEnum ;
182
+
183
+ let enumerator = self . as_str( ) ;
184
+ if enumerator. is_empty( ) {
185
+ #enumerator_not_found
186
+ }
187
+ }
188
+ } else {
189
+ let enumerators = make_enum_to_str_cases ( enum_) ;
190
+
191
+ quote ! {
192
+ // Many enums have duplicates, thus allow unreachable.
193
+ // In the future, we could print sth like "ONE|TWO" instead (at least for unstable Debug).
194
+ #[ allow( unreachable_patterns) ]
195
+ let enumerator = match * self {
196
+ #enumerators
197
+ _ => {
198
+ #enumerator_not_found
199
+ }
200
+ } ;
201
+ }
202
+ } ;
203
+
162
204
quote ! {
163
205
impl std:: fmt:: Debug for #enum_name {
164
206
fn fmt( & self , f: & mut std:: fmt:: Formatter <' _>) -> std:: fmt:: Result {
165
- // Many enums have duplicates, thus allow unreachable.
166
- // In the future, we could print sth like "ONE|TWO" instead (at least for unstable Debug).
167
- #[ allow( unreachable_patterns) ]
168
- let enumerator = match * self {
169
- #( #enumerators ) *
170
- _ => {
171
- f. debug_struct( #enum_name_str)
172
- . field( "ord" , & self . ord)
173
- . finish( ) ?;
174
- return Ok ( ( ) ) ;
175
- }
176
- } ;
177
-
207
+ #function_body
178
208
f. write_str( enumerator)
179
209
}
180
210
}
@@ -222,6 +252,8 @@ fn make_enum_engine_trait_impl(enum_: &Enum) -> TokenStream {
222
252
}
223
253
} ) ;
224
254
255
+ let str_functions = make_enum_str_functions ( enum_) ;
256
+
225
257
quote ! {
226
258
impl #engine_trait for #name {
227
259
fn try_from_ord( ord: i32 ) -> Option <Self > {
@@ -234,10 +266,13 @@ fn make_enum_engine_trait_impl(enum_: &Enum) -> TokenStream {
234
266
fn ord( self ) -> i32 {
235
267
self as i32
236
268
}
269
+
270
+ #str_functions
237
271
}
238
272
}
239
273
} else {
240
274
let unique_ords = enum_. unique_ords ( ) . expect ( "self is an enum" ) ;
275
+ let str_functions = make_enum_str_functions ( enum_) ;
241
276
242
277
quote ! {
243
278
impl #engine_trait for #name {
@@ -251,8 +286,70 @@ fn make_enum_engine_trait_impl(enum_: &Enum) -> TokenStream {
251
286
fn ord( self ) -> i32 {
252
287
self . ord
253
288
}
289
+
290
+ #str_functions
291
+ }
292
+ }
293
+ }
294
+ }
295
+
296
+ /// Creates the `as_str` and `godot_name` implementations for the enum.
297
+ fn make_enum_str_functions ( enum_ : & Enum ) -> TokenStream {
298
+ let as_str_enumerators = make_enum_to_str_cases ( enum_) ;
299
+
300
+ // Only enumerations with different godot names are specified.
301
+ // `as_str` is called for the rest of them.
302
+ let godot_different_cases = {
303
+ let enumerators = enum_
304
+ . enumerators
305
+ . iter ( )
306
+ . filter ( |enumerator| enumerator. name != enumerator. godot_name )
307
+ . map ( |enumerator| {
308
+ let Enumerator {
309
+ name, godot_name, ..
310
+ } = enumerator;
311
+ let godot_name_str = godot_name. to_string ( ) ;
312
+ quote ! {
313
+ Self :: #name => #godot_name_str,
314
+ }
315
+ } ) ;
316
+
317
+ quote ! {
318
+ #( #enumerators ) *
319
+ }
320
+ } ;
321
+
322
+ let godot_name_match = if godot_different_cases. is_empty ( ) {
323
+ // If empty, all the Rust names match the Godot ones.
324
+ // Remove match statement to avoid `clippy::match_single_binding`.
325
+ quote ! {
326
+ self . as_str( )
327
+ }
328
+ } else {
329
+ quote ! {
330
+ // Many enums have duplicates, thus allow unreachable.
331
+ #[ allow( unreachable_patterns) ]
332
+ match * self {
333
+ #godot_different_cases
334
+ _ => self . as_str( ) ,
254
335
}
255
336
}
337
+ } ;
338
+
339
+ quote ! {
340
+ #[ inline]
341
+ fn as_str( & self ) -> & ' static str {
342
+ // Many enums have duplicates, thus allow unreachable.
343
+ #[ allow( unreachable_patterns) ]
344
+ match * self {
345
+ #as_str_enumerators
346
+ _ => "" ,
347
+ }
348
+ }
349
+
350
+ fn godot_name( & self ) -> & ' static str {
351
+ #godot_name_match
352
+ }
256
353
}
257
354
}
258
355
0 commit comments