@@ -97,10 +97,13 @@ pub fn make_enum_definition_with(
97
97
} ;
98
98
99
99
let traits = define_traits. then ( || {
100
- // Trait implementations
101
- let engine_trait_impl = make_enum_engine_trait_impl ( enum_) ;
100
+ // Check for associated bitmasks (e.g. Key -> KeyModifierMask).
101
+ let enum_bitmask = special_cases:: as_enum_bitmaskable ( enum_) ;
102
+
103
+ // Trait implementations.
104
+ let engine_trait_impl = make_enum_engine_trait_impl ( enum_, enum_bitmask. as_ref ( ) ) ;
102
105
let index_enum_impl = make_enum_index_impl ( enum_) ;
103
- let bitwise_impls = make_enum_bitwise_operators ( enum_) ;
106
+ let bitwise_impls = make_enum_bitwise_operators ( enum_, enum_bitmask . as_ref ( ) ) ;
104
107
105
108
quote ! {
106
109
#engine_trait_impl
@@ -216,11 +219,13 @@ fn make_enum_debug_impl(enum_: &Enum, use_as_str: bool) -> TokenStream {
216
219
/// Creates an implementation of the engine trait for the given enum.
217
220
///
218
221
/// This will implement the trait returned by [`Enum::engine_trait`].
219
- fn make_enum_engine_trait_impl ( enum_ : & Enum ) -> TokenStream {
222
+ fn make_enum_engine_trait_impl ( enum_ : & Enum , enum_bitmask : Option < & RustTy > ) -> TokenStream {
220
223
let name = & enum_. name ;
221
224
let engine_trait = enum_. engine_trait ( ) ;
222
225
223
226
if enum_. is_bitfield {
227
+ // Bitfields: u64, assume any combination is valid.
228
+
224
229
quote ! {
225
230
// We may want to add this in the future.
226
231
//
@@ -239,6 +244,8 @@ fn make_enum_engine_trait_impl(enum_: &Enum) -> TokenStream {
239
244
}
240
245
}
241
246
} else if enum_. is_exhaustive {
247
+ // Exhaustive enums: Rust representation is C-style `enum` (not `const`), no fallback enumerator.
248
+
242
249
let enumerators = enum_. enumerators . iter ( ) . map ( |enumerator| {
243
250
let Enumerator {
244
251
name,
@@ -273,16 +280,36 @@ fn make_enum_engine_trait_impl(enum_: &Enum) -> TokenStream {
273
280
}
274
281
}
275
282
} else {
283
+ // Non-exhaustive enums divide into two categories:
284
+ // - Those with associated mask (e.g. Key -> KeyModifierMask)
285
+ // - All others
286
+ // Both have a Rust representation of `struct { ord: i32 }`, with their values as `const` declarations.
287
+ // However, those with masks don't have strict validation when marshalling from integers, and a Debug repr which includes the mask.
288
+
276
289
let unique_ords = enum_. unique_ords ( ) . expect ( "self is an enum" ) ;
277
290
let str_functions = make_enum_str_functions ( enum_) ;
278
291
292
+ // We can technically check against all possible mask values, remove each mask, and then verify it's a valid base-enum value.
293
+ // However, this is not forward compatible: if a new mask is added in a future API version, it wouldn't be removed, and the
294
+ // "unmasked" (all *known* masks removed) value would not match an enumerator. Thus, assume the value is valid, even if at lower
295
+ // type safety.
296
+ let try_from_ord_code = if let Some ( _mask) = enum_bitmask {
297
+ quote ! {
298
+ Some ( Self { ord } )
299
+ }
300
+ } else {
301
+ quote ! {
302
+ match ord {
303
+ #( ord @ #unique_ords ) |* => Some ( Self { ord } ) ,
304
+ _ => None ,
305
+ }
306
+ }
307
+ } ;
308
+
279
309
quote ! {
280
310
impl #engine_trait for #name {
281
311
fn try_from_ord( ord: i32 ) -> Option <Self > {
282
- match ord {
283
- #( ord @ #unique_ords ) |* => Some ( Self { ord } ) ,
284
- _ => None ,
285
- }
312
+ #try_from_ord_code
286
313
}
287
314
288
315
fn ord( self ) -> i32 {
@@ -358,7 +385,7 @@ fn make_enum_str_functions(enum_: &Enum) -> TokenStream {
358
385
/// Creates implementations for bitwise operators for the given enum.
359
386
///
360
387
/// Currently, this is just [`BitOr`](std::ops::BitOr) for bitfields but that could be expanded in the future.
361
- fn make_enum_bitwise_operators ( enum_ : & Enum ) -> TokenStream {
388
+ fn make_enum_bitwise_operators ( enum_ : & Enum , enum_bitmask : Option < & RustTy > ) -> TokenStream {
362
389
let name = & enum_. name ;
363
390
364
391
if enum_. is_bitfield {
@@ -380,7 +407,7 @@ fn make_enum_bitwise_operators(enum_: &Enum) -> TokenStream {
380
407
}
381
408
}
382
409
}
383
- } else if let Some ( mask_enum) = special_cases :: as_enum_bitmaskable ( enum_ ) {
410
+ } else if let Some ( mask_enum) = enum_bitmask {
384
411
// Enum that has an accompanying bitfield for masking.
385
412
let RustTy :: EngineEnum { tokens : mask, .. } = mask_enum else {
386
413
panic ! ( "as_enum_bitmaskable() must return enum/bitfield type" )
0 commit comments