@@ -241,8 +241,37 @@ pub fn make_enum_definition(enum_: &Enum) -> TokenStream {
241
241
unique_ords. sort ( ) ;
242
242
unique_ords. dedup ( ) ;
243
243
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 ! {
246
275
// impl #enum_name {
247
276
// pub const UNSET: Self = Self { ord: 0 };
248
277
// }
@@ -254,97 +283,85 @@ pub fn make_enum_definition(enum_: &Enum) -> TokenStream {
254
283
}
255
284
}
256
285
} ;
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
+ }
257
293
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
+ }
267
297
}
268
- }
298
+ } ;
269
299
} 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
+ }
275
319
}
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
- }
285
320
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
+ }
290
324
}
291
- }
292
- } else {
293
- TokenStream :: new ( )
325
+ } ;
294
326
} ;
295
327
296
- let derives = derives. into_iter ( ) . map ( ident) ;
297
-
298
328
// Enumerator ordinal stored as i32, since that's enough to hold all current values and the default repr in C++.
299
329
// 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
301
331
quote ! {
302
332
#[ repr( transparent) ]
303
333
#[ derive( #( #derives ) , * ) ]
304
334
pub struct #enum_name {
305
- ord: i32
335
+ ord: #enum_ord_type
306
336
}
307
337
impl #enum_name {
308
338
#(
309
339
#enumerators
310
340
) *
311
341
}
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
- // }
321
342
322
- #try_from_ord
343
+ #engine_impl
344
+
345
+ #bitfield_ops
323
346
324
- fn ord( self ) -> i32 {
325
- self . ord
326
- }
327
- }
328
347
#index_enum_impl
329
348
330
349
impl crate :: builtin:: meta:: GodotConvert for #enum_name {
331
- type Via = i32 ;
350
+ type Via = #enum_ord_type ;
332
351
}
333
352
334
353
impl crate :: builtin:: meta:: ToGodot for #enum_name {
335
354
fn to_godot( & self ) -> Self :: Via {
336
- < Self as crate :: obj :: EngineEnum > :: ord( * self )
355
+ #self_as_trait :: ord( * self )
337
356
}
338
357
}
339
358
340
359
impl crate :: builtin:: meta:: FromGodot for #enum_name {
341
360
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)
343
362
. ok_or_else( || crate :: builtin:: meta:: FromGodotError :: InvalidEnum . into_error( via) )
344
363
}
345
364
}
346
-
347
- #bitfield_ops
348
365
}
349
366
}
350
367
@@ -670,11 +687,28 @@ fn to_rust_type_uncached(full_ty: &GodotTy, ctx: &mut Context) -> RustTy {
670
687
} ;
671
688
}
672
689
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
+ }
676
710
677
- if let Some ( qualified_enum) = qualified_enum {
711
+ if let Some ( qualified_enum) = ty . strip_prefix ( "enum::" ) {
678
712
return if let Some ( ( class, enum_) ) = qualified_enum. split_once ( '.' ) {
679
713
// Class-local enum
680
714
let module = ModName :: from_godot ( class) ;
@@ -799,6 +833,7 @@ fn to_rust_expr_inner(expr: &str, ty: &RustTy, is_inner: bool) -> TokenStream {
799
833
if let Ok ( num) = expr. parse :: < i64 > ( ) {
800
834
let lit = Literal :: i64_unsuffixed ( num) ;
801
835
return match ty {
836
+ RustTy :: EngineBitfield { .. } => quote ! { crate :: obj:: EngineBitfield :: from_ord( #lit) } ,
802
837
RustTy :: EngineEnum { .. } => quote ! { crate :: obj:: EngineEnum :: from_ord( #lit) } ,
803
838
RustTy :: BuiltinIdent ( ident) if ident == "Variant" => quote ! { Variant :: from( #lit) } ,
804
839
RustTy :: BuiltinIdent ( ident)
@@ -948,6 +983,12 @@ fn gdscript_to_rust_expr() {
948
983
} ;
949
984
let ty_enum = Some ( & ty_enum) ;
950
985
986
+ let ty_bitfield = RustTy :: EngineBitfield {
987
+ tokens : quote ! { SomeEnum } ,
988
+ surrounding_class : None ,
989
+ } ;
990
+ let ty_bitfield = Some ( & ty_bitfield) ;
991
+
951
992
let ty_variant = RustTy :: BuiltinIdent ( ident ( "Variant" ) ) ;
952
993
let ty_variant = Some ( & ty_variant) ;
953
994
@@ -997,6 +1038,9 @@ fn gdscript_to_rust_expr() {
997
1038
// enum (from int)
998
1039
( "7" , ty_enum, quote ! { crate :: obj:: EngineEnum :: from_ord( 7 ) } ) ,
999
1040
1041
+ // bitfield (from int)
1042
+ ( "7" , ty_bitfield, quote ! { crate :: obj:: EngineBitfield :: from_ord( 7 ) } ) ,
1043
+
1000
1044
// Variant (from int)
1001
1045
( "8" , ty_variant, quote ! { Variant :: from( 8 ) } ) ,
1002
1046
0 commit comments