7
7
8
8
//! Different ways how bounds of a `GodotClass` can be checked.
9
9
//!
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:
11
11
//!
12
12
//! 1. [`Declarer`] tells you whether the class is provided by the engine or user-defined.
13
13
//! - [`DeclEngine`] is used for all classes provided by the engine (e.g. `Node3D`).
19
19
//! - [`MemRefCounted`] is used for `RefCounted` classes and derived.
20
20
//! - [`MemManual`] is used for `Object` and all inherited classes, which are not `RefCounted` (e.g. `Node`).<br><br>
21
21
//!
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.
31
32
//!
32
33
//!
33
34
//! # Example
44
45
//! }
45
46
//! ```
46
47
//!
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`.
48
49
49
50
use crate :: obj:: cap:: GodotDefault ;
50
51
use crate :: obj:: { Bounds , Gd , GodotClass , RawGd } ;
@@ -86,6 +87,10 @@ pub(super) mod private {
86
87
/// Defines the memory strategy of the static type.
87
88
type Memory : Memory ;
88
89
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) ]
89
94
/// Defines the memory strategy of the instance (at runtime).
90
95
type DynMemory : DynMemory ;
91
96
@@ -146,6 +151,7 @@ pub trait Memory: Sealed {}
146
151
/// Specifies the memory strategy of the dynamic type.
147
152
///
148
153
/// For `Gd<Object>`, it is determined at runtime whether the instance is manually managed or ref-counted.
154
+ #[ doc( hidden) ]
149
155
pub trait DynMemory : Sealed {
150
156
/// Initialize reference counter
151
157
#[ doc( hidden) ]
@@ -175,6 +181,10 @@ pub trait DynMemory: Sealed {
175
181
#[ doc( hidden) ]
176
182
fn is_ref_counted < T : GodotClass > ( obj : & RawGd < T > ) -> Option < bool > ;
177
183
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
+
178
188
/// Returns `true` if argument and return pointers are passed as `Ref<T>` pointers given this
179
189
/// [`PtrcallType`].
180
190
///
@@ -236,38 +246,46 @@ impl DynMemory for MemRefCounted {
236
246
Some ( true )
237
247
}
238
248
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
+
239
256
fn pass_as_ref ( call_type : sys:: PtrcallType ) -> bool {
240
257
matches ! ( call_type, sys:: PtrcallType :: Virtual )
241
258
}
242
259
}
243
260
244
261
/// Memory managed through Godot reference counter, if present; otherwise manual.
245
262
/// This is used only for `Object` classes.
263
+ #[ doc( hidden) ]
246
264
pub 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
+ }
247
273
impl Sealed for MemDynamic { }
248
274
impl DynMemory for MemDynamic {
249
275
fn maybe_init_ref < T : GodotClass > ( obj : & mut RawGd < T > ) {
250
276
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) {
256
278
// Will call `RefCounted::init_ref()` which checks for liveness.
257
- out ! ( "MemDyn -> MemRefc" ) ;
279
+ out ! ( " MemDyn -> MemRefc" ) ;
258
280
MemRefCounted :: maybe_init_ref ( obj)
259
281
} else {
260
- out ! ( "MemDyn -> MemManu" ) ;
282
+ out ! ( " MemDyn -> MemManu" ) ;
261
283
}
262
284
}
263
285
264
286
fn maybe_inc_ref < T : GodotClass > ( obj : & mut RawGd < T > ) {
265
287
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) {
271
289
// Will call `RefCounted::reference()` which checks for liveness.
272
290
MemRefCounted :: maybe_inc_ref ( obj)
273
291
}
@@ -291,6 +309,14 @@ impl DynMemory for MemDynamic {
291
309
// Return `None` if obj is dead
292
310
obj. instance_id_unchecked ( ) . map ( |id| id. is_ref_counted ( ) )
293
311
}
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
+ }
294
320
}
295
321
296
322
/// No memory management, user responsible for not leaking.
@@ -307,6 +333,9 @@ impl DynMemory for MemManual {
307
333
fn is_ref_counted < T : GodotClass > ( _obj : & RawGd < T > ) -> Option < bool > {
308
334
Some ( false )
309
335
}
336
+ fn get_ref_count < T : GodotClass > ( _obj : & RawGd < T > ) -> Option < usize > {
337
+ None
338
+ }
310
339
}
311
340
312
341
// ----------------------------------------------------------------------------------------------------------------------------------------------
0 commit comments