Skip to content

Commit 8ec6a22

Browse files
authored
Merge pull request #486 from godot-rust/qol/gd-constructors
Rework `Gd` constructors, add `default()` to engine classes
2 parents 3605f0f + 8281437 commit 8ec6a22

File tree

19 files changed

+309
-158
lines changed

19 files changed

+309
-158
lines changed

godot-codegen/src/class_generator.rs

+27-10
Original file line numberDiff line numberDiff line change
@@ -441,44 +441,58 @@ fn make_module_doc(class_name: &TyName) -> String {
441441
)
442442
}
443443

444-
fn make_constructor(class: &Class, ctx: &Context) -> TokenStream {
444+
fn make_constructor_and_default(
445+
class: &Class,
446+
class_name: &TyName,
447+
ctx: &Context,
448+
) -> (TokenStream, TokenStream) {
445449
let godot_class_name = &class.name;
446450
let godot_class_stringname = make_string_name(godot_class_name);
447451
// Note: this could use class_name() but is not yet done due to upcoming lazy-load refactoring.
448452
//let class_name_obj = quote! { <Self as crate::obj::GodotClass>::class_name() };
449453

454+
let (constructor, godot_default_impl);
450455
if ctx.is_singleton(godot_class_name) {
451456
// Note: we cannot return &'static mut Self, as this would be very easy to mutably alias.
452457
// &'static Self would be possible, but we would lose the whole mutability information (even if that is best-effort and
453458
// not strict Rust mutability, it makes the API much more usable).
454459
// As long as the user has multiple Gd smart pointers to the same singletons, only the internal raw pointers are aliased.
455460
// See also Deref/DerefMut impl for Gd.
456-
quote! {
461+
constructor = quote! {
457462
pub fn singleton() -> Gd<Self> {
458463
unsafe {
459464
let __class_name = #godot_class_stringname;
460465
let __object_ptr = sys::interface_fn!(global_get_singleton)(__class_name.string_sys());
461466
Gd::from_obj_sys(__object_ptr)
462467
}
463468
}
464-
}
469+
};
470+
godot_default_impl = TokenStream::new();
465471
} else if !class.is_instantiable {
466472
// Abstract base classes or non-singleton classes without constructor
467-
TokenStream::new()
473+
constructor = TokenStream::new();
474+
godot_default_impl = TokenStream::new();
468475
} else if class.is_refcounted {
469476
// RefCounted, Resource, etc
470-
quote! {
477+
constructor = quote! {
471478
pub fn new() -> Gd<Self> {
472479
unsafe {
473480
let class_name = #godot_class_stringname;
474481
let object_ptr = sys::interface_fn!(classdb_construct_object)(class_name.string_sys());
475482
Gd::from_obj_sys(object_ptr)
476483
}
477484
}
478-
}
485+
};
486+
godot_default_impl = quote! {
487+
impl crate::obj::cap::GodotDefault for #class_name {
488+
fn __godot_default() -> crate::obj::Gd<Self> {
489+
Self::new()
490+
}
491+
}
492+
};
479493
} else {
480494
// Manually managed classes: Object, Node etc
481-
quote! {
495+
constructor = quote! {
482496
#[must_use]
483497
pub fn new_alloc() -> Gd<Self> {
484498
unsafe {
@@ -487,8 +501,11 @@ fn make_constructor(class: &Class, ctx: &Context) -> TokenStream {
487501
Gd::from_obj_sys(object_ptr)
488502
}
489503
}
490-
}
504+
};
505+
godot_default_impl = TokenStream::new();
491506
}
507+
508+
(constructor, godot_default_impl)
492509
}
493510

494511
fn make_class(class: &Class, class_name: &TyName, ctx: &mut Context) -> GeneratedClass {
@@ -506,7 +523,7 @@ fn make_class(class: &Class, class_name: &TyName, ctx: &mut Context) -> Generate
506523
None => (quote! { () }, None),
507524
};
508525

509-
let constructor = make_constructor(class, ctx);
526+
let (constructor, godot_default_impl) = make_constructor_and_default(class, class_name, ctx);
510527
let api_level = util::get_api_level(class);
511528
let init_level = api_level.to_init_level();
512529

@@ -640,7 +657,7 @@ fn make_class(class: &Class, class_name: &TyName, ctx: &mut Context) -> Generate
640657
)*
641658

642659
#exportable_impl
643-
660+
#godot_default_impl
644661
#deref_impl
645662

646663
#[macro_export]

godot-core/src/builtin/string/gstring.rs

+8-8
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,6 @@ impl GString {
8585
.expect("Godot hashes are uint32_t")
8686
}
8787

88-
/// Move `self` into a system pointer. This transfers ownership and thus does not call the destructor.
89-
///
90-
/// # Safety
91-
/// `dst` must be a pointer to a `GString` which is suitable for ffi with Godot.
92-
pub unsafe fn move_string_ptr(self, dst: sys::GDExtensionStringPtr) {
93-
self.move_return_ptr(dst as *mut _, sys::PtrcallType::Standard);
94-
}
95-
9688
/// Gets the internal chars slice from a [`GString`].
9789
///
9890
/// Note: This operation is *O*(*n*). Consider using [`chars_unchecked`][Self::chars_unchecked]
@@ -140,6 +132,14 @@ impl GString {
140132
fn string_sys = sys;
141133
}
142134

135+
/// Move `self` into a system pointer. This transfers ownership and thus does not call the destructor.
136+
///
137+
/// # Safety
138+
/// `dst` must be a pointer to a `GString` which is suitable for ffi with Godot.
139+
pub(crate) unsafe fn move_string_ptr(self, dst: sys::GDExtensionStringPtr) {
140+
self.move_return_ptr(dst as *mut _, sys::PtrcallType::Standard);
141+
}
142+
143143
#[doc(hidden)]
144144
pub fn as_inner(&self) -> inner::InnerString {
145145
inner::InnerString::from_outer(self)

godot-core/src/obj/gd.rs

+106-39
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@
66

77
use std::fmt::{Debug, Display, Formatter, Result as FmtResult};
88
use std::ops::{Deref, DerefMut};
9-
use std::ptr;
109

1110
use godot_ffi as sys;
1211
use godot_ffi::VariantType;
@@ -23,28 +22,65 @@ use super::RawGd;
2322

2423
/// Smart pointer to objects owned by the Godot engine.
2524
///
25+
/// See also [chapter about objects][book] in the book.
26+
///
2627
/// This smart pointer can only hold _objects_ in the Godot sense: instances of Godot classes (`Node`, `RefCounted`, etc.)
27-
/// or user-declared structs (`#[derive(GodotClass)]`). It does **not** hold built-in types (`Vector3`, `Color`, `i32`).
28+
/// or user-declared structs (declared with `#[derive(GodotClass)]`). It does **not** hold built-in types (`Vector3`, `Color`, `i32`).
2829
///
2930
/// `Gd<T>` never holds null objects. If you need nullability, use `Option<Gd<T>>`.
3031
///
32+
/// # Memory management
33+
///
3134
/// This smart pointer behaves differently depending on `T`'s associated types, see [`GodotClass`] for their documentation.
3235
/// In particular, the memory management strategy is fully dependent on `T`:
3336
///
34-
/// * Objects of type [`RefCounted`] or inherited from it are **reference-counted**. This means that every time a smart pointer is
37+
/// - **Reference-counted**<br>
38+
/// Objects of type [`RefCounted`] or inherited from it are **reference-counted**. This means that every time a smart pointer is
3539
/// shared using [`Clone::clone()`], the reference counter is incremented, and every time one is dropped, it is decremented.
36-
/// This ensures that the last reference (either in Rust or Godot) will deallocate the object and call `T`'s destructor.
40+
/// This ensures that the last reference (either in Rust or Godot) will deallocate the object and call `T`'s destructor.<br><br>
3741
///
38-
/// * Objects inheriting from [`Object`] which are not `RefCounted` (or inherited) are **manually-managed**.
42+
/// - **Manual**<br>
43+
/// Objects inheriting from [`Object`] which are not `RefCounted` (or inherited) are **manually-managed**.
3944
/// Their destructor is not automatically called (unless they are part of the scene tree). Creating a `Gd<T>` means that
40-
/// you are responsible of explicitly deallocating such objects using [`Gd::free()`].
45+
/// you are responsible of explicitly deallocating such objects using [`free()`][Self::free].<br><br>
4146
///
42-
/// * For `T=Object`, the memory strategy is determined **dynamically**. Due to polymorphism, a `Gd<T>` can point to either
47+
/// - **Dynamic**<br>
48+
/// For `T=Object`, the memory strategy is determined **dynamically**. Due to polymorphism, a `Gd<Object>` can point to either
4349
/// reference-counted or manually-managed types at runtime. The behavior corresponds to one of the two previous points.
4450
/// Note that if the dynamic type is also `Object`, the memory is manually-managed.
4551
///
46-
/// [`Object`]: crate::engine::Object
47-
/// [`RefCounted`]: crate::engine::RefCounted
52+
/// # Construction
53+
///
54+
/// To construct default instances of various `Gd<T>` types, there are extension methods on the type `T` itself:
55+
///
56+
/// | Type \ Memory Strategy | Ref-counted | Manually managed | Singleton |
57+
/// |------------------------|----------------------|-----------------------|-------------------------|
58+
/// | **Engine type** | `Resource::new()` | `Node::new_alloc()` | `Os::singleton()` |
59+
/// | **User type** | `MyClass::new_gd()` | `MyClass::alloc_gd()` | _(not yet implemented)_ |
60+
///
61+
/// In addition, the smart pointer can be constructed in multiple ways:
62+
///
63+
/// * [`Gd::default()`] for reference-counted types that are constructible. For user types, this means they must expose an `init` function
64+
/// or have a generated one. `Gd::<T>::default()` is equivalent to the shorter `T::new_gd()` and primarily useful for derives or generics.
65+
/// * [`Gd::from_init_fn(function)`][Gd::from_init_fn] for Rust objects with `#[base]` field, which are constructed inside the smart pointer.
66+
/// This is a very handy function if you want to pass extra parameters to your object upon construction.
67+
/// * [`Gd::from_object(rust_obj)`][Gd::from_object] for existing Rust objects without a `#[base]` field that are moved _into_ the smart pointer.
68+
/// * [`Gd::from_instance_id(id)`][Gd::from_instance_id] and [`Gd::try_from_instance_id(id)`][Gd::try_from_instance_id]
69+
/// to obtain a pointer to an object which is already alive in the engine.
70+
///
71+
/// # Binds
72+
///
73+
/// The [`bind()`][Self::bind] and [`bind_mut()`][Self::bind_mut] methods allow you to obtain a shared or exclusive guard to the user instance.
74+
/// These provide interior mutability similar to [`RefCell`][std::cell::RefCell], with the addition that `Gd` simultaneously handles reference
75+
/// counting (for some types `T`).
76+
///
77+
/// When you declare a `#[func]` method on your own class and it accepts `&self` or `&mut self`, an implicit `bind()` or `bind_mut()` call
78+
/// on the owning `Gd<T>` is performed. This is important to keep in mind, as you can get into situations that violate dynamic borrow rules; for
79+
/// example if you are inside a `&mut self` method, make a call to GDScript and indirectly call another method on the same object (re-entrancy).
80+
///
81+
/// [book]: https://godot-rust.github.io/book/intro/objects.html
82+
/// [`Object`]: engine::Object
83+
/// [`RefCounted`]: engine::RefCounted
4884
#[repr(C)] // must be layout compatible with engine classes
4985
pub struct Gd<T: GodotClass> {
5086
// Note: `opaque` has the same layout as GDExtensionObjectPtr == Object* in C++, i.e. the bytes represent a pointer
@@ -68,27 +104,6 @@ impl<T> Gd<T>
68104
where
69105
T: GodotClass<Declarer = dom::UserDomain>,
70106
{
71-
/// Moves a user-created object into this smart pointer, submitting ownership to the Godot engine.
72-
///
73-
/// This is only useful for types `T` which do not store their base objects (if they have a base,
74-
/// you cannot construct them standalone).
75-
pub fn new(user_object: T) -> Self {
76-
Self::with_base(move |_base| user_object)
77-
}
78-
79-
/// Creates a default-constructed instance of `T` inside a smart pointer.
80-
///
81-
/// This is equivalent to the GDScript expression `T.new()`.
82-
pub fn new_default() -> Self
83-
where
84-
T: cap::GodotInit,
85-
{
86-
unsafe {
87-
let object_ptr = callbacks::create::<T>(ptr::null_mut());
88-
Gd::from_obj_sys(object_ptr)
89-
}
90-
}
91-
92107
/// Creates a `Gd<T>` using a function that constructs a `T` from a provided base.
93108
///
94109
/// Imagine you have a type `T`, which has a `#[base]` field that you cannot default-initialize.
@@ -106,19 +121,48 @@ where
106121
/// other_field: i32,
107122
/// }
108123
///
109-
/// let obj = Gd::<MyClass>::with_base(|my_base| {
124+
/// let obj = Gd::from_init_fn(|my_base| {
110125
/// // accepts the base and returns a constructed object containing it
111126
/// MyClass { my_base, other_field: 732 }
112127
/// });
113128
/// ```
114-
pub fn with_base<F>(init: F) -> Self
129+
pub fn from_init_fn<F>(init: F) -> Self
115130
where
116131
F: FnOnce(crate::obj::Base<T::Base>) -> T,
117132
{
118133
let object_ptr = callbacks::create_custom(init);
119134
unsafe { Gd::from_obj_sys(object_ptr) }
120135
}
121136

137+
/// Moves a user-created object into this smart pointer, submitting ownership to the Godot engine.
138+
///
139+
/// This is only useful for types `T` which do not store their base objects (if they have a base,
140+
/// you cannot construct them standalone).
141+
pub fn from_object(user_object: T) -> Self {
142+
Self::from_init_fn(move |_base| user_object)
143+
}
144+
145+
#[deprecated = "Use `Gd::from_object()` instead."]
146+
pub fn new(user_object: T) -> Self {
147+
Self::from_object(user_object)
148+
}
149+
150+
#[deprecated = "Use `Gd::default()` or the short-hands `T::new_gd()` and `T::alloc_gd()` instead."]
151+
pub fn new_default() -> Self
152+
where
153+
T: cap::GodotDefault,
154+
{
155+
Self::default_instance()
156+
}
157+
158+
#[deprecated = "Use `Gd::from_init_fn()` instead."]
159+
pub fn with_base<F>(init: F) -> Self
160+
where
161+
F: FnOnce(crate::obj::Base<T::Base>) -> T,
162+
{
163+
Self::from_init_fn(init)
164+
}
165+
122166
/// Hands out a guard for a shared borrow, through which the user instance can be read.
123167
///
124168
/// The pattern is very similar to interior mutability with standard [`RefCell`][std::cell::RefCell].
@@ -242,7 +286,7 @@ impl<T: GodotClass> Gd<T> {
242286
/// #[class(init, base=Node2D)]
243287
/// struct MyClass {}
244288
///
245-
/// let obj: Gd<MyClass> = Gd::new_default();
289+
/// let obj: Gd<MyClass> = MyClass::alloc_gd();
246290
/// let base = obj.clone().upcast::<Node>();
247291
/// ```
248292
pub fn upcast<Base>(self) -> Gd<Base>
@@ -295,7 +339,19 @@ impl<T: GodotClass> Gd<T> {
295339
.map_err(Self::from_ffi)
296340
}
297341

298-
#[doc(hidden)]
342+
/// Create default instance for all types that have `GodotDefault`.
343+
///
344+
/// Deliberately more loose than `Gd::default()`, does not require ref-counted memory strategy for user types.
345+
pub(crate) fn default_instance() -> Self
346+
where
347+
T: cap::GodotDefault,
348+
{
349+
unsafe {
350+
let object_ptr = crate::callbacks::create::<T>(std::ptr::null_mut());
351+
Gd::from_obj_sys(object_ptr)
352+
}
353+
}
354+
299355
pub(crate) unsafe fn from_obj_sys_or_none(ptr: sys::GDExtensionObjectPtr) -> Option<Self> {
300356
Self::try_from_ffi(RawGd::from_obj_sys(ptr))
301357
}
@@ -305,26 +361,21 @@ impl<T: GodotClass> Gd<T> {
305361
///
306362
/// This is the default for most initializations from FFI. In cases where reference counter
307363
/// should explicitly **not** be updated, [`Self::from_obj_sys_weak`] is available.
308-
#[doc(hidden)]
309364
pub(crate) unsafe fn from_obj_sys(ptr: sys::GDExtensionObjectPtr) -> Self {
310365
Self::from_obj_sys_or_none(ptr).unwrap()
311366
}
312367

313-
#[doc(hidden)]
314368
pub(crate) unsafe fn from_obj_sys_weak_or_none(ptr: sys::GDExtensionObjectPtr) -> Option<Self> {
315369
Self::try_from_ffi(RawGd::from_obj_sys_weak(ptr))
316370
}
317371

318-
#[doc(hidden)]
319372
pub(crate) unsafe fn from_obj_sys_weak(ptr: sys::GDExtensionObjectPtr) -> Self {
320373
Self::from_obj_sys_weak_or_none(ptr).unwrap()
321374
}
322375

323-
#[doc(hidden)]
324376
pub(crate) fn obj_sys(&self) -> sys::GDExtensionObjectPtr {
325377
self.raw.obj_sys()
326378
}
327-
328379
/// Returns a callable referencing a method from this object named `method_name`.
329380
pub fn callable<S: Into<StringName>>(&self, method_name: S) -> Callable {
330381
Callable::from_object_method(self.clone(), method_name)
@@ -486,6 +537,22 @@ impl<T: GodotClass> GodotType for Gd<T> {
486537
}
487538
}
488539

540+
impl<T> Default for Gd<T>
541+
where
542+
T: cap::GodotDefault + GodotClass<Mem = mem::StaticRefCount>,
543+
{
544+
/// Creates a default-constructed `T` inside a smart pointer.
545+
///
546+
/// This is equivalent to the GDScript expression `T.new()`, and to the shorter Rust expression `T::new_gd()`.
547+
///
548+
/// This trait is only implemented for reference-counted classes. Classes with manually-managed memory (e.g. `Node`) are not covered,
549+
/// because they need explicit memory management, and deriving `Default` has a high chance of the user forgetting to call `free()` on those.
550+
/// `T::alloc_gd()` should be used for those instead.
551+
fn default() -> Self {
552+
T::__godot_default()
553+
}
554+
}
555+
489556
impl<T: GodotClass> Clone for Gd<T> {
490557
fn clone(&self) -> Self {
491558
out!("Gd::clone");

0 commit comments

Comments
 (0)