@@ -80,10 +80,10 @@ struct GeneratedClassModule {
80
80
}
81
81
82
82
struct Construction {
83
- constructor : TokenStream ,
84
83
construct_doc : & ' static str ,
85
84
final_doc : Option < & ' static str > ,
86
85
godot_default_impl : TokenStream ,
86
+ singleton_impl : TokenStream ,
87
87
}
88
88
89
89
fn make_class ( class : & Class , ctx : & mut Context , view : & ApiView ) -> GeneratedClass {
@@ -102,10 +102,10 @@ fn make_class(class: &Class, ctx: &mut Context, view: &ApiView) -> GeneratedClas
102
102
} ;
103
103
104
104
let Construction {
105
- constructor,
106
105
construct_doc,
107
106
final_doc,
108
107
godot_default_impl,
108
+ singleton_impl,
109
109
} = make_constructor_and_default ( class, ctx) ;
110
110
111
111
let mut extended_class_doc = construct_doc. replace ( "Self" , & class_name. rust_ty . to_string ( ) ) ;
@@ -234,7 +234,7 @@ fn make_class(class: &Class, ctx: &mut Context, view: &ApiView) -> GeneratedClas
234
234
#interface_trait
235
235
#notification_enum
236
236
impl #class_name {
237
- #constructor
237
+ // Constructors all through traits: NewGd, NewAlloc, Singleton.
238
238
#methods
239
239
#notify_methods
240
240
#internal_methods
@@ -267,6 +267,7 @@ fn make_class(class: &Class, ctx: &mut Context, view: &ApiView) -> GeneratedClas
267
267
) *
268
268
269
269
#godot_default_impl
270
+ #singleton_impl
270
271
#deref_impl
271
272
#inherits_macro_code
272
273
}
@@ -424,34 +425,18 @@ fn make_constructor_and_default(class: &Class, ctx: &Context) -> Construction {
424
425
// Note: this could use class_id() but is not yet done due to potential future lazy-load refactoring.
425
426
//let class_name_obj = quote! { <Self as crate::obj::GodotClass>::class_id() };
426
427
427
- let ( constructor , construct_doc, has_godot_default_impl) ;
428
+ let ( construct_doc, has_godot_default_impl) ;
428
429
if ctx. is_singleton ( class_name) {
429
- // Note: we cannot return &'static mut Self, as this would be very easy to mutably alias.
430
- // &'static Self would be possible, but we would lose the whole mutability information (even if that is best-effort and
431
- // not strict Rust mutability, it makes the API much more usable).
432
- // As long as the user has multiple Gd smart pointers to the same singletons, only the internal raw pointers are aliased.
433
- // See also Deref/DerefMut impl for Gd.
434
- constructor = quote ! {
435
- pub fn singleton( ) -> Gd <Self > {
436
- unsafe {
437
- let __class_name = #godot_class_stringname;
438
- let __object_ptr = sys:: interface_fn!( global_get_singleton) ( __class_name. string_sys( ) ) ;
439
- Gd :: from_obj_sys( __object_ptr)
440
- }
441
- }
442
- } ;
443
430
construct_doc = "# Singleton\n \n \
444
- This class is a singleton. You can get the one instance using [`Self ::singleton()`][Self ::singleton].";
431
+ This class is a singleton. You can get the one instance using [`Singleton ::singleton()`][crate::obj::Singleton ::singleton].";
445
432
has_godot_default_impl = false ;
446
433
} else if !class. is_instantiable {
447
434
// Abstract base classes or non-singleton classes without constructor.
448
- constructor = TokenStream :: new ( ) ;
449
435
construct_doc = "# Not instantiable\n \n This class cannot be constructed. Obtain `Gd<Self>` instances via Godot APIs." ;
450
436
has_godot_default_impl = false ;
451
437
} else {
452
438
// Manually managed classes (Object, Node, ...) as well as ref-counted ones (RefCounted, Resource, ...).
453
439
// The constructors are provided as associated methods in NewGd::new_gd() and NewAlloc::new_alloc().
454
- constructor = TokenStream :: new ( ) ;
455
440
456
441
if class. is_refcounted {
457
442
construct_doc = "# Construction\n \n \
@@ -488,11 +473,25 @@ fn make_constructor_and_default(class: &Class, ctx: &Context) -> Construction {
488
473
TokenStream :: new ( )
489
474
} ;
490
475
476
+ let singleton_impl = if ctx. is_singleton ( class_name) {
477
+ let class_name = & class. name ( ) . rust_ty ;
478
+ quote ! {
479
+ impl crate :: obj:: Singleton for #class_name {
480
+ fn singleton( ) -> crate :: obj:: Gd <Self > {
481
+ // SAFETY: Class name matches type T, per code generator.
482
+ unsafe { crate :: classes:: singleton_unchecked( & #godot_class_stringname) }
483
+ }
484
+ }
485
+ }
486
+ } else {
487
+ TokenStream :: new ( )
488
+ } ;
489
+
491
490
Construction {
492
- constructor,
493
491
construct_doc,
494
492
final_doc,
495
493
godot_default_impl,
494
+ singleton_impl,
496
495
}
497
496
}
498
497
@@ -573,8 +572,6 @@ fn make_class_method_definition(
573
572
return FnDefinition :: none ( ) ;
574
573
} ;
575
574
576
- // Note: parameter type replacements (int -> enum) are already handled during domain mapping.
577
-
578
575
let rust_class_name = class. name ( ) . rust_ty . to_string ( ) ;
579
576
let rust_method_name = method. name ( ) ;
580
577
let godot_method_name = method. godot_name ( ) ;
0 commit comments