77
88//! Different ways how bounds of a `GodotClass` can be checked.
99//!
10- //! This module contains three traits that can be used to check the characteristics of a `GodotClass` type:
10+ //! This module contains multiple traits that can be used to check the characteristics of a `GodotClass` type:
1111//!
1212//! 1. [`Declarer`] tells you whether the class is provided by the engine or user-defined.
1313//! - [`DeclEngine`] is used for all classes provided by the engine (e.g. `Node3D`).
1919//! - [`MemRefCounted`] is used for `RefCounted` classes and derived.
2020//! - [`MemManual`] is used for `Object` and all inherited classes, which are not `RefCounted` (e.g. `Node`).<br><br>
2121//!
22- //! 3. [`DynMemory`] is used to check the memory strategy of the **dynamic** type.
23- //!
24- //! When you operate on methods of `T` or `Gd<T>` and are interested in instances, you can use this.
25- //! Most of the time, this is not what you want -- just use `Memory` if you want to know if a type is manually managed or ref-counted.
26- //! - [`MemRefCounted`] is used for `RefCounted` classes and derived. These are **always** reference-counted.
27- //! - [`MemManual`] is used instances inheriting `Object`, which are not `RefCounted` (e.g. `Node`). Excludes `Object` itself. These are
28- //! **always** manually managed.
29- //! - [`MemDynamic`] is used for `Object` instances. `Gd<Object>` can point to objects of any possible class, so whether we are dealing with
30- //! a ref-counted or manually-managed object is determined only at runtime.
22+ // FIXME excluded because broken; see below.
23+ // 3. [`DynMemory`] is used to check the memory strategy of the **dynamic** type.
24+ //
25+ // When you operate on methods of `T` or `Gd<T>` and are interested in instances, you can use this.
26+ // Most of the time, this is not what you want -- just use `Memory` if you want to know if a type is manually managed or ref-counted.
27+ // - [`MemRefCounted`] is used for `RefCounted` classes and derived. These are **always** reference-counted.
28+ // - [`MemManual`] is used instances inheriting `Object`, which are not `RefCounted` (e.g. `Node`). Excludes `Object` itself. These are
29+ // **always** manually managed.
30+ // - [`MemDynamic`] is used for `Object` instances. `Gd<Object>` can point to objects of any possible class, so whether we are dealing with
31+ // a ref-counted or manually-managed object is determined only at runtime.
3132//!
3233//!
3334//! # Example
4445//! }
4546//! ```
4647//!
47- //! Note that depending on if you want to exclude `Object`, you should use `DynMemory` instead of `Memory`.
48+ // Note that depending on if you want to exclude `Object`, you should use `DynMemory` instead of `Memory`.
4849
4950use crate :: obj:: cap:: GodotDefault ;
5051use crate :: obj:: { Bounds , Gd , GodotClass , RawGd } ;
@@ -86,6 +87,10 @@ pub(super) mod private {
8687 /// Defines the memory strategy of the static type.
8788 type Memory : Memory ;
8889
90+ // FIXME: this is broken as a bound: one cannot use T: Bounds<DynMemory = MemRefCounted> to include Object AND RefCounted,
91+ // since Object itself has DynMemory = MemDynamic. Needs to either use traits like in gdnative, or more types to account for
92+ // different combinations (as only positive ones can be expressed, not T: Bounds<Memory != MemManual>).
93+ #[ doc( hidden) ]
8994 /// Defines the memory strategy of the instance (at runtime).
9095 type DynMemory : DynMemory ;
9196
@@ -146,6 +151,7 @@ pub trait Memory: Sealed {}
146151/// Specifies the memory strategy of the dynamic type.
147152///
148153/// For `Gd<Object>`, it is determined at runtime whether the instance is manually managed or ref-counted.
154+ #[ doc( hidden) ]
149155pub trait DynMemory : Sealed {
150156 /// Initialize reference counter
151157 #[ doc( hidden) ]
@@ -175,6 +181,10 @@ pub trait DynMemory: Sealed {
175181 #[ doc( hidden) ]
176182 fn is_ref_counted < T : GodotClass > ( obj : & RawGd < T > ) -> Option < bool > ;
177183
184+ /// Return the reference count, or `None` if the object is dead or manually managed.
185+ #[ doc( hidden) ]
186+ fn get_ref_count < T : GodotClass > ( obj : & RawGd < T > ) -> Option < usize > ;
187+
178188 /// Returns `true` if argument and return pointers are passed as `Ref<T>` pointers given this
179189 /// [`PtrcallType`].
180190 ///
@@ -236,38 +246,46 @@ impl DynMemory for MemRefCounted {
236246 Some ( true )
237247 }
238248
249+ fn get_ref_count < T : GodotClass > ( obj : & RawGd < T > ) -> Option < usize > {
250+ let ref_count = obj. with_ref_counted ( |refc| refc. get_reference_count ( ) ) ;
251+
252+ // TODO find a safer cast alternative, e.g. num-traits crate with ToPrimitive (Debug) + AsPrimitive (Release).
253+ Some ( ref_count as usize )
254+ }
255+
239256 fn pass_as_ref ( call_type : sys:: PtrcallType ) -> bool {
240257 matches ! ( call_type, sys:: PtrcallType :: Virtual )
241258 }
242259}
243260
244261/// Memory managed through Godot reference counter, if present; otherwise manual.
245262/// This is used only for `Object` classes.
263+ #[ doc( hidden) ]
246264pub struct MemDynamic { }
265+ impl MemDynamic {
266+ /// Check whether dynamic type is ref-counted.
267+ fn inherits_refcounted < T : GodotClass > ( obj : & RawGd < T > ) -> bool {
268+ obj. instance_id_unchecked ( )
269+ . map ( |id| id. is_ref_counted ( ) )
270+ . unwrap_or ( false )
271+ }
272+ }
247273impl Sealed for MemDynamic { }
248274impl DynMemory for MemDynamic {
249275 fn maybe_init_ref < T : GodotClass > ( obj : & mut RawGd < T > ) {
250276 out ! ( " MemDyn::init <{}>" , std:: any:: type_name:: <T >( ) ) ;
251- if obj
252- . instance_id_unchecked ( )
253- . map ( |id| id. is_ref_counted ( ) )
254- . unwrap_or ( false )
255- {
277+ if Self :: inherits_refcounted ( obj) {
256278 // Will call `RefCounted::init_ref()` which checks for liveness.
257- out ! ( "MemDyn -> MemRefc" ) ;
279+ out ! ( " MemDyn -> MemRefc" ) ;
258280 MemRefCounted :: maybe_init_ref ( obj)
259281 } else {
260- out ! ( "MemDyn -> MemManu" ) ;
282+ out ! ( " MemDyn -> MemManu" ) ;
261283 }
262284 }
263285
264286 fn maybe_inc_ref < T : GodotClass > ( obj : & mut RawGd < T > ) {
265287 out ! ( " MemDyn::inc <{}>" , std:: any:: type_name:: <T >( ) ) ;
266- if obj
267- . instance_id_unchecked ( )
268- . map ( |id| id. is_ref_counted ( ) )
269- . unwrap_or ( false )
270- {
288+ if Self :: inherits_refcounted ( obj) {
271289 // Will call `RefCounted::reference()` which checks for liveness.
272290 MemRefCounted :: maybe_inc_ref ( obj)
273291 }
@@ -291,6 +309,14 @@ impl DynMemory for MemDynamic {
291309 // Return `None` if obj is dead
292310 obj. instance_id_unchecked ( ) . map ( |id| id. is_ref_counted ( ) )
293311 }
312+
313+ fn get_ref_count < T : GodotClass > ( obj : & RawGd < T > ) -> Option < usize > {
314+ if Self :: inherits_refcounted ( obj) {
315+ MemRefCounted :: get_ref_count ( obj)
316+ } else {
317+ None
318+ }
319+ }
294320}
295321
296322/// No memory management, user responsible for not leaking.
@@ -307,6 +333,9 @@ impl DynMemory for MemManual {
307333 fn is_ref_counted < T : GodotClass > ( _obj : & RawGd < T > ) -> Option < bool > {
308334 Some ( false )
309335 }
336+ fn get_ref_count < T : GodotClass > ( _obj : & RawGd < T > ) -> Option < usize > {
337+ None
338+ }
310339}
311340
312341// ----------------------------------------------------------------------------------------------------------------------------------------------
0 commit comments