Skip to content

Commit e43b480

Browse files
committed
Register reference/unreference callbacks for RefCounted classes
1 parent eceae18 commit e43b480

File tree

3 files changed

+28
-5
lines changed

3 files changed

+28
-5
lines changed

godot-core/src/obj/bounds.rs

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -152,7 +152,11 @@ pub use crate::implement_godot_bounds;
152152
// Memory bounds
153153

154154
/// Specifies the memory strategy of the static type.
155-
pub trait Memory: Sealed {}
155+
pub trait Memory: Sealed {
156+
/// True for everything inheriting `RefCounted`, false for `Object` and all other classes.
157+
#[doc(hidden)]
158+
const IS_REF_COUNTED: bool;
159+
}
156160

157161
/// Specifies the memory strategy of the dynamic type.
158162
///
@@ -205,7 +209,9 @@ pub trait DynMemory: Sealed {
205209
/// This is used for `RefCounted` classes and derived.
206210
pub struct MemRefCounted {}
207211
impl Sealed for MemRefCounted {}
208-
impl Memory for MemRefCounted {}
212+
impl Memory for MemRefCounted {
213+
const IS_REF_COUNTED: bool = true;
214+
}
209215
impl DynMemory for MemRefCounted {
210216
fn maybe_init_ref<T: GodotClass>(obj: &mut RawGd<T>) {
211217
out!(" MemRefc::init: {obj:?}");
@@ -327,7 +333,9 @@ impl DynMemory for MemDynamic {
327333
/// This is used for all `Object` derivates, which are not `RefCounted`. `Object` itself is also excluded.
328334
pub struct MemManual {}
329335
impl Sealed for MemManual {}
330-
impl Memory for MemManual {}
336+
impl Memory for MemManual {
337+
const IS_REF_COUNTED: bool = false;
338+
}
331339
impl DynMemory for MemManual {
332340
fn maybe_init_ref<T: GodotClass>(_obj: &mut RawGd<T>) {}
333341
fn maybe_inc_ref<T: GodotClass>(_obj: &mut RawGd<T>) {}

godot-core/src/registry/class.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -136,8 +136,8 @@ impl ClassRegistrationInfo {
136136
}
137137

138138
/// Registers a class with static type information.
139-
// Currently dead code, but will be needed for builder API. Don't remove.
140-
pub fn register_class<
139+
#[expect(dead_code)] // Will be needed for builder API. Don't remove.
140+
pub(crate) fn register_class<
141141
T: cap::GodotDefault
142142
+ cap::ImplementsGodotVirtual
143143
+ cap::GodotToString
@@ -427,6 +427,8 @@ fn fill_class_info(item: PluginItem, c: &mut ClassRegistrationInfo) {
427427
is_instantiable,
428428
#[cfg(all(since_api = "4.3", feature = "register-docs"))]
429429
docs: _,
430+
reference_fn,
431+
unreference_fn,
430432
}) => {
431433
c.parent_class_name = Some(base_class_name);
432434
c.default_virtual_fn = default_get_virtual_fn;
@@ -443,6 +445,8 @@ fn fill_class_info(item: PluginItem, c: &mut ClassRegistrationInfo) {
443445
// See also: https://github.com/godotengine/godot/pull/58972
444446
c.godot_params.is_abstract = sys::conv::bool_to_sys(!is_instantiable);
445447
c.godot_params.free_instance_func = Some(free_fn);
448+
c.godot_params.reference_func = reference_fn;
449+
c.godot_params.unreference_func = unreference_fn;
446450

447451
fill_into(
448452
&mut c.godot_params.create_instance_func,

godot-core/src/registry/plugin.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,12 @@ pub struct Struct {
167167
/// Callback to library-generated function which registers properties in the `struct` definition.
168168
pub(crate) register_properties_fn: ErasedRegisterFn,
169169

170+
/// Callback on refc-increment. Only for `RefCounted` classes.
171+
pub(crate) reference_fn: sys::GDExtensionClassReference,
172+
173+
/// Callback on refc-decrement. Only for `RefCounted` classes.
174+
pub(crate) unreference_fn: sys::GDExtensionClassUnreference,
175+
170176
/// Function called by Godot when an object of this class is freed.
171177
///
172178
/// Always implemented as [`callbacks::free`].
@@ -200,6 +206,8 @@ impl Struct {
200206
pub fn new<T: GodotClass + cap::ImplementsGodotExports>(
201207
#[cfg(all(since_api = "4.3", feature = "register-docs"))] docs: StructDocs,
202208
) -> Self {
209+
let refcounted = <T::Memory as bounds::Memory>::IS_REF_COUNTED;
210+
203211
Self {
204212
base_class_name: T::Base::class_name(),
205213
generated_create_fn: None,
@@ -215,6 +223,9 @@ impl Struct {
215223
is_instantiable: false,
216224
#[cfg(all(since_api = "4.3", feature = "register-docs"))]
217225
docs,
226+
// While Godot doesn't do anything with these callbacks for non-RefCounted classes, we can avoid instantiating them in Rust.
227+
reference_fn: refcounted.then_some(callbacks::reference::<T>),
228+
unreference_fn: refcounted.then_some(callbacks::unreference::<T>),
218229
}
219230
}
220231

0 commit comments

Comments
 (0)