5
5
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
6
6
*/
7
7
8
- use std:: marker:: PhantomData ;
9
8
use std:: mem:: ManuallyDrop ;
10
9
use std:: ops:: { Deref , DerefMut } ;
11
10
12
11
use crate :: obj:: { Gd , GodotClass } ;
12
+ use crate :: sys;
13
13
14
14
/// Passive (non-owning) reference to a Godot object.
15
15
///
16
- /// `PassiveGd<'gd, T>` provides a safe abstraction for weak references to Godot objects. Unlike `Gd<T>`, it does not increment/decrement
16
+ /// `PassiveGd<T>` provides an unsafe abstraction for weak references to Godot objects. Unlike `Gd<T>`, it does not increment/decrement
17
17
/// the reference count for `RefCounted` objects, and its `Drop` impl only cleans up metadata, not the Godot object.
18
18
///
19
- /// The lifetime `'gd` can be used to tie it to a _strong_ `Gd<T>` reference, however it can also be `'static` if more flexibility is needed.
19
+ /// This type is for internal use only, to access base objects in guards and traits, and to wrap manual [`Gd::clone_weak()`] and
20
+ /// [`Gd::drop_weak()`] patterns.
20
21
///
21
- /// This type is primarily used internally for base object access in guards and traits, providing a clean alternative to manual
22
- /// [`Gd::clone_weak()`] and [`Gd::drop_weak()`] patterns.
23
- pub ( crate ) struct PassiveGd < ' gd , T : GodotClass > {
22
+ /// # Why no lifetime?
23
+ /// Previous versions used `PassiveGd<'gd, T>` with an explicit lifetime parameter. This caused subtle borrow-checking issues due to Rust's
24
+ /// [drop check](https://doc.rust-lang.org/nomicon/dropck.html) rules. When a type has drop obligations (implements `Drop` or contains fields
25
+ /// that do), the borrow checker conservatively assumes the destructor might access borrowed data reachable through that value, forcing all
26
+ /// such borrows to strictly outlive the value. This created false conflicts when creating both shared and mutable base references from the
27
+ /// same object, even though our `Drop` implementation never accesses the lifetime-bound data.
28
+ ///
29
+ /// By removing the lifetime parameter and making construction `unsafe`, we eliminate these false-positive borrow conflicts while maintaining
30
+ /// memory safety through explicit caller contracts.
31
+ ///
32
+ /// In nightly Rust, `#[may_dangle]` on the lifetime parameter might be an alternative, to tell the compiler that our `Drop` implementation
33
+ /// won't access the borrowed data, but this attribute requires careful safety analysis to ensure it's correctly applied.
34
+ pub ( crate ) struct PassiveGd < T : GodotClass > {
24
35
weak_gd : ManuallyDrop < Gd < T > > ,
25
-
26
- // Covariant lifetime: PassiveGd<'a, T> can be used wherever PassiveGd<'b, T> is needed, if 'a: 'b.
27
- _phantom : PhantomData < & ' gd ( ) > ,
28
36
}
29
37
30
- impl < ' gd , T : GodotClass > PassiveGd < ' gd , T > {
31
- pub fn from_strong_ref ( gd : & Gd < T > ) -> Self {
32
- // SAFETY:
33
- // - `clone_weak()` creates a pointer conforming to `from_weak_gd()` requirements.
34
- // - PassiveGd will destroy the pointer with `drop_weak()`.
38
+ impl < T : GodotClass > PassiveGd < T > {
39
+ /// Creates a passive reference from a strong `Gd<T>` shared reference.
40
+ ///
41
+ /// # Safety
42
+ /// The caller must ensure that the underlying object remains valid for the entire lifetime of this `PassiveGd`.
43
+ pub unsafe fn from_strong_ref ( gd : & Gd < T > ) -> Self {
44
+ // SAFETY: clone_weak() creates valid weak reference; caller ensures object validity.
45
+ let weak_gd = gd. clone_weak ( ) ;
46
+ unsafe { Self :: new ( weak_gd) }
47
+ }
48
+
49
+ /// Creates a passive reference directly from a raw object pointer.
50
+ ///
51
+ /// This is a direct constructor that avoids the intermediate `Gd::from_obj_sys_weak()` step,
52
+ /// providing better performance for the common pattern of creating PassiveGd from raw pointers.
53
+ ///
54
+ /// # Safety
55
+ /// - `obj_ptr` must be a valid, live object pointer.
56
+ /// - The caller must ensure that the underlying object remains valid for the entire lifetime of this `PassiveGd`.
57
+ pub unsafe fn from_obj_sys ( obj_ptr : sys:: GDExtensionObjectPtr ) -> Self {
58
+ // SAFETY: from_obj_sys_weak() creates valid weak reference from obj_ptr; caller ensures object validity.
35
59
unsafe {
36
- let weak_gd = gd . clone_weak ( ) ;
37
- Self :: from_weak_owned ( weak_gd)
60
+ let weak_gd = Gd :: from_obj_sys_weak ( obj_ptr ) ;
61
+ Self :: new ( weak_gd)
38
62
}
39
63
}
40
64
41
65
/// Creates a passive reference directly from a weak `Gd<T>`.
42
66
///
43
- /// Will invoke `Gd::drop_weak()` when dropped. Since the parameter has no lifetime, you need to provide the lifetime `'gd` explicitly.
67
+ /// Will invoke `Gd::drop_weak()` when dropped.
44
68
///
45
69
/// # Safety
46
70
/// - `weak_gd` must be a weakly created `Gd`, e.g. from [`Gd::clone_weak()`] or [`Gd::from_obj_sys_weak()`].
47
- /// - The caller must ensure that the `weak_gd` remains valid for the lifetime `'gd `.
48
- pub unsafe fn from_weak_owned ( weak_gd : Gd < T > ) -> Self {
71
+ /// - The caller must ensure that the underlying object remains valid for the entire lifetime of this `PassiveGd `.
72
+ unsafe fn new ( weak_gd : Gd < T > ) -> Self {
49
73
Self {
50
74
weak_gd : ManuallyDrop :: new ( weak_gd) ,
51
- _phantom : PhantomData ,
52
75
}
53
76
}
54
77
}
55
78
56
- impl < T : GodotClass > Drop for PassiveGd < ' _ , T > {
79
+ impl < T : GodotClass > Drop for PassiveGd < T > {
57
80
fn drop ( & mut self ) {
58
81
// SAFETY: Only extracted once, in Drop.
59
82
let weak = unsafe { ManuallyDrop :: take ( & mut self . weak_gd ) } ;
@@ -62,15 +85,15 @@ impl<T: GodotClass> Drop for PassiveGd<'_, T> {
62
85
}
63
86
}
64
87
65
- impl < T : GodotClass > Deref for PassiveGd < ' _ , T > {
88
+ impl < T : GodotClass > Deref for PassiveGd < T > {
66
89
type Target = Gd < T > ;
67
90
68
91
fn deref ( & self ) -> & Self :: Target {
69
92
& self . weak_gd
70
93
}
71
94
}
72
95
73
- impl < T : GodotClass > DerefMut for PassiveGd < ' _ , T > {
96
+ impl < T : GodotClass > DerefMut for PassiveGd < T > {
74
97
fn deref_mut ( & mut self ) -> & mut Self :: Target {
75
98
& mut self . weak_gd
76
99
}
0 commit comments