@@ -241,8 +241,37 @@ pub fn make_enum_definition(enum_: &Enum) -> TokenStream {
241241 unique_ords. sort ( ) ;
242242 unique_ords. dedup ( ) ;
243243
244- let bitfield_ops = if enum_. is_bitfield {
245- let tokens = quote ! {
244+ let mut derives = vec ! [ "Copy" , "Clone" , "Eq" , "PartialEq" , "Hash" , "Debug" ] ;
245+
246+ if enum_. is_bitfield {
247+ derives. push ( "Default" ) ;
248+ }
249+
250+ let derives = derives. into_iter ( ) . map ( ident) ;
251+
252+ let index_enum_impl = if enum_. is_bitfield {
253+ // Bitfields don't implement IndexEnum.
254+ TokenStream :: new ( )
255+ } else {
256+ // Enums implement IndexEnum only if they are "index-like" (see docs).
257+ if let Some ( enum_max) = try_count_index_enum ( enum_) {
258+ quote ! {
259+ impl crate :: obj:: IndexEnum for #enum_name {
260+ const ENUMERATOR_COUNT : usize = #enum_max;
261+ }
262+ }
263+ } else {
264+ TokenStream :: new ( )
265+ }
266+ } ;
267+
268+ let bitfield_ops;
269+ let self_as_trait;
270+ let engine_impl;
271+ let enum_ord_type;
272+
273+ if enum_. is_bitfield {
274+ bitfield_ops = quote ! {
246275 // impl #enum_name {
247276 // pub const UNSET: Self = Self { ord: 0 };
248277 // }
@@ -254,97 +283,85 @@ pub fn make_enum_definition(enum_: &Enum) -> TokenStream {
254283 }
255284 }
256285 } ;
286+ enum_ord_type = quote ! { u64 } ;
287+ self_as_trait = quote ! { <Self as crate :: obj:: EngineBitfield > } ;
288+ engine_impl = quote ! {
289+ impl crate :: obj:: EngineBitfield for #enum_name {
290+ fn try_from_ord( ord: u64 ) -> Option <Self > {
291+ Some ( Self { ord } )
292+ }
257293
258- Some ( tokens)
259- } else {
260- None
261- } ;
262-
263- let try_from_ord = if enum_. is_bitfield {
264- quote ! {
265- fn try_from_ord( ord: i32 ) -> Option <Self > {
266- Some ( Self { ord } )
294+ fn ord( self ) -> u64 {
295+ self . ord
296+ }
267297 }
268- }
298+ } ;
269299 } else {
270- quote ! {
271- fn try_from_ord( ord: i32 ) -> Option <Self > {
272- match ord {
273- #( ord @ #unique_ords ) |* => Some ( Self { ord } ) ,
274- _ => None ,
300+ bitfield_ops = TokenStream :: new ( ) ;
301+ enum_ord_type = quote ! { i32 } ;
302+ self_as_trait = quote ! { <Self as crate :: obj:: EngineEnum > } ;
303+ engine_impl = quote ! {
304+ impl crate :: obj:: EngineEnum for #enum_name {
305+ // fn try_from_ord(ord: i32) -> Option<Self> {
306+ // match ord {
307+ // #(
308+ // #matches
309+ // )*
310+ // _ => None,
311+ // }
312+ // }
313+
314+ fn try_from_ord( ord: i32 ) -> Option <Self > {
315+ match ord {
316+ #( ord @ #unique_ords ) |* => Some ( Self { ord } ) ,
317+ _ => None ,
318+ }
275319 }
276- }
277- }
278- } ;
279-
280- let mut derives = vec ! [ "Copy" , "Clone" , "Eq" , "PartialEq" , "Debug" , "Hash" ] ;
281-
282- if enum_. is_bitfield {
283- derives. push ( "Default" ) ;
284- }
285320
286- let index_enum_impl = if let Some ( enum_max) = try_count_index_enum ( enum_) {
287- quote ! {
288- impl crate :: obj:: IndexEnum for #enum_name {
289- const ENUMERATOR_COUNT : usize = #enum_max;
321+ fn ord( self ) -> i32 {
322+ self . ord
323+ }
290324 }
291- }
292- } else {
293- TokenStream :: new ( )
325+ } ;
294326 } ;
295327
296- let derives = derives. into_iter ( ) . map ( ident) ;
297-
298328 // Enumerator ordinal stored as i32, since that's enough to hold all current values and the default repr in C++.
299329 // Public interface is i64 though, for consistency (and possibly forward compatibility?).
300- // TODO maybe generalize GodotFfi over EngineEnum trait
330+ // Bitfield ordinals are stored as u64. See also: https://github.com/godotengine/godot-cpp/pull/1320
301331 quote ! {
302332 #[ repr( transparent) ]
303333 #[ derive( #( #derives ) , * ) ]
304334 pub struct #enum_name {
305- ord: i32
335+ ord: #enum_ord_type
306336 }
307337 impl #enum_name {
308338 #(
309339 #enumerators
310340 ) *
311341 }
312- impl crate :: obj:: EngineEnum for #enum_name {
313- // fn try_from_ord(ord: i32) -> Option<Self> {
314- // match ord {
315- // #(
316- // #matches
317- // )*
318- // _ => None,
319- // }
320- // }
321342
322- #try_from_ord
343+ #engine_impl
344+
345+ #bitfield_ops
323346
324- fn ord( self ) -> i32 {
325- self . ord
326- }
327- }
328347 #index_enum_impl
329348
330349 impl crate :: builtin:: meta:: GodotConvert for #enum_name {
331- type Via = i32 ;
350+ type Via = #enum_ord_type ;
332351 }
333352
334353 impl crate :: builtin:: meta:: ToGodot for #enum_name {
335354 fn to_godot( & self ) -> Self :: Via {
336- < Self as crate :: obj :: EngineEnum > :: ord( * self )
355+ #self_as_trait :: ord( * self )
337356 }
338357 }
339358
340359 impl crate :: builtin:: meta:: FromGodot for #enum_name {
341360 fn try_from_godot( via: Self :: Via ) -> std:: result:: Result <Self , crate :: builtin:: meta:: ConvertError > {
342- < Self as crate :: obj :: EngineEnum > :: try_from_ord( via)
361+ #self_as_trait :: try_from_ord( via)
343362 . ok_or_else( || crate :: builtin:: meta:: FromGodotError :: InvalidEnum . into_error( via) )
344363 }
345364 }
346-
347- #bitfield_ops
348365 }
349366}
350367
@@ -670,11 +687,28 @@ fn to_rust_type_uncached(full_ty: &GodotTy, ctx: &mut Context) -> RustTy {
670687 } ;
671688 }
672689
673- let qualified_enum = ty
674- . strip_prefix ( "enum::" )
675- . or_else ( || ty. strip_prefix ( "bitfield::" ) ) ;
690+ if let Some ( bitfield) = ty. strip_prefix ( "bitfield::" ) {
691+ return if let Some ( ( class, enum_) ) = bitfield. split_once ( '.' ) {
692+ // Class-local bitfield.
693+ let module = ModName :: from_godot ( class) ;
694+ let bitfield_ty = make_enum_name ( enum_) ;
695+
696+ RustTy :: EngineBitfield {
697+ tokens : quote ! { crate :: engine:: #module:: #bitfield_ty} ,
698+ surrounding_class : Some ( class. to_string ( ) ) ,
699+ }
700+ } else {
701+ // Global bitfield.
702+ let bitfield_ty = make_enum_name ( bitfield) ;
703+
704+ RustTy :: EngineBitfield {
705+ tokens : quote ! { crate :: engine:: global:: #bitfield_ty } ,
706+ surrounding_class : None ,
707+ }
708+ } ;
709+ }
676710
677- if let Some ( qualified_enum) = qualified_enum {
711+ if let Some ( qualified_enum) = ty . strip_prefix ( "enum::" ) {
678712 return if let Some ( ( class, enum_) ) = qualified_enum. split_once ( '.' ) {
679713 // Class-local enum
680714 let module = ModName :: from_godot ( class) ;
@@ -799,6 +833,7 @@ fn to_rust_expr_inner(expr: &str, ty: &RustTy, is_inner: bool) -> TokenStream {
799833 if let Ok ( num) = expr. parse :: < i64 > ( ) {
800834 let lit = Literal :: i64_unsuffixed ( num) ;
801835 return match ty {
836+ RustTy :: EngineBitfield { .. } => quote ! { crate :: obj:: EngineBitfield :: from_ord( #lit) } ,
802837 RustTy :: EngineEnum { .. } => quote ! { crate :: obj:: EngineEnum :: from_ord( #lit) } ,
803838 RustTy :: BuiltinIdent ( ident) if ident == "Variant" => quote ! { Variant :: from( #lit) } ,
804839 RustTy :: BuiltinIdent ( ident)
@@ -948,6 +983,12 @@ fn gdscript_to_rust_expr() {
948983 } ;
949984 let ty_enum = Some ( & ty_enum) ;
950985
986+ let ty_bitfield = RustTy :: EngineBitfield {
987+ tokens : quote ! { SomeEnum } ,
988+ surrounding_class : None ,
989+ } ;
990+ let ty_bitfield = Some ( & ty_bitfield) ;
991+
951992 let ty_variant = RustTy :: BuiltinIdent ( ident ( "Variant" ) ) ;
952993 let ty_variant = Some ( & ty_variant) ;
953994
@@ -997,6 +1038,9 @@ fn gdscript_to_rust_expr() {
9971038 // enum (from int)
9981039 ( "7" , ty_enum, quote ! { crate :: obj:: EngineEnum :: from_ord( 7 ) } ) ,
9991040
1041+ // bitfield (from int)
1042+ ( "7" , ty_bitfield, quote ! { crate :: obj:: EngineBitfield :: from_ord( 7 ) } ) ,
1043+
10001044 // Variant (from int)
10011045 ( "8" , ty_variant, quote ! { Variant :: from( 8 ) } ) ,
10021046
0 commit comments