@@ -13,6 +13,7 @@ use crate::models::domain::{Enum, Enumerator, EnumeratorValue, RustTy};
13
13
use crate :: special_cases;
14
14
use proc_macro2:: TokenStream ;
15
15
use quote:: { quote, ToTokens } ;
16
+ use std:: collections:: HashSet ;
16
17
17
18
pub fn make_enums ( enums : & [ Enum ] , cfg_attributes : & TokenStream ) -> TokenStream {
18
19
let definitions = enums. iter ( ) . map ( make_enum_definition) ;
@@ -141,7 +142,7 @@ pub fn make_enum_definition_with(
141
142
///
142
143
/// Returns `None` if `enum_` isn't an indexable enum.
143
144
fn make_enum_index_impl ( enum_ : & Enum ) -> Option < TokenStream > {
144
- let enum_max = enum_. find_index_enum_max ( ) ? ;
145
+ let enum_max = enum_. max_index ? ; // Do nothing if enum isn't sequential with a MAX constant.
145
146
let name = & enum_. name ;
146
147
147
148
Some ( quote ! {
@@ -226,6 +227,8 @@ fn make_enum_engine_trait_impl(enum_: &Enum, enum_bitmask: Option<&RustTy>) -> T
226
227
if enum_. is_bitfield {
227
228
// Bitfields: u64, assume any combination is valid.
228
229
230
+ let constants_function = make_all_constants_function ( enum_) ;
231
+
229
232
quote ! {
230
233
// We may want to add this in the future.
231
234
//
@@ -241,6 +244,8 @@ fn make_enum_engine_trait_impl(enum_: &Enum, enum_bitmask: Option<&RustTy>) -> T
241
244
fn ord( self ) -> u64 {
242
245
self . ord
243
246
}
247
+
248
+ #constants_function
244
249
}
245
250
}
246
251
} else if enum_. is_exhaustive {
@@ -262,6 +267,7 @@ fn make_enum_engine_trait_impl(enum_: &Enum, enum_bitmask: Option<&RustTy>) -> T
262
267
} ) ;
263
268
264
269
let str_functions = make_enum_str_functions ( enum_) ;
270
+ let values_and_constants_functions = make_enum_values_and_constants_functions ( enum_) ;
265
271
266
272
quote ! {
267
273
impl #engine_trait for #name {
@@ -277,6 +283,7 @@ fn make_enum_engine_trait_impl(enum_: &Enum, enum_bitmask: Option<&RustTy>) -> T
277
283
}
278
284
279
285
#str_functions
286
+ #values_and_constants_functions
280
287
}
281
288
}
282
289
} else {
@@ -288,6 +295,7 @@ fn make_enum_engine_trait_impl(enum_: &Enum, enum_bitmask: Option<&RustTy>) -> T
288
295
289
296
let unique_ords = enum_. unique_ords ( ) . expect ( "self is an enum" ) ;
290
297
let str_functions = make_enum_str_functions ( enum_) ;
298
+ let values_and_constants_functions = make_enum_values_and_constants_functions ( enum_) ;
291
299
292
300
// We can technically check against all possible mask values, remove each mask, and then verify it's a valid base-enum value.
293
301
// However, this is not forward compatible: if a new mask is added in a future API version, it wouldn't be removed, and the
@@ -317,6 +325,65 @@ fn make_enum_engine_trait_impl(enum_: &Enum, enum_bitmask: Option<&RustTy>) -> T
317
325
}
318
326
319
327
#str_functions
328
+ #values_and_constants_functions
329
+ }
330
+ }
331
+ }
332
+ }
333
+
334
+ /// Creates both the `values()` and `all_constants()` implementations for the enum.
335
+ fn make_enum_values_and_constants_functions ( enum_ : & Enum ) -> TokenStream {
336
+ let name = & enum_. name ;
337
+
338
+ let mut distinct_values = Vec :: new ( ) ;
339
+ let mut seen_ordinals = HashSet :: new ( ) ;
340
+
341
+ for ( index, enumerator) in enum_. enumerators . iter ( ) . enumerate ( ) {
342
+ let constant = & enumerator. name ;
343
+ let ordinal = & enumerator. value ;
344
+
345
+ // values() contains value only if distinct (first time seen) and not MAX.
346
+ if enum_. max_index != Some ( index) && seen_ordinals. insert ( ordinal. clone ( ) ) {
347
+ distinct_values. push ( quote ! { #name:: #constant } ) ;
348
+ }
349
+ }
350
+
351
+ let values_function = quote ! {
352
+ fn values( ) -> & ' static [ Self ] {
353
+ & [
354
+ #( #distinct_values ) , *
355
+ ]
356
+ }
357
+ } ;
358
+
359
+ let all_constants_function = make_all_constants_function ( enum_) ;
360
+
361
+ quote ! {
362
+ #values_function
363
+ #all_constants_function
364
+ }
365
+ }
366
+
367
+ /// Creates a shared `all_constants()` implementation for enums and bitfields.
368
+ fn make_all_constants_function ( enum_ : & Enum ) -> TokenStream {
369
+ let name = & enum_. name ;
370
+
371
+ let all_constants = enum_. enumerators . iter ( ) . map ( |enumerator| {
372
+ let ident = & enumerator. name ;
373
+ let rust_name = enumerator. name . to_string ( ) ;
374
+ let godot_name = enumerator. godot_name . to_string ( ) ;
375
+
376
+ quote ! {
377
+ crate :: meta:: inspect:: EnumConstant :: new( #rust_name, #godot_name, #name:: #ident)
378
+ }
379
+ } ) ;
380
+
381
+ quote ! {
382
+ fn all_constants( ) -> & ' static [ crate :: meta:: inspect:: EnumConstant <#name>] {
383
+ const {
384
+ & [
385
+ #( #all_constants ) , *
386
+ ]
320
387
}
321
388
}
322
389
}
0 commit comments