Skip to main content

godot_core/obj/
guards.rs

1/*
2 * Copyright (c) godot-rust; Bromeon and contributors.
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at https://mozilla.org/MPL/2.0/.
6 */
7
8use std::fmt::Debug;
9use std::ops::{Deref, DerefMut};
10
11#[cfg(feature = "experimental-threads")] #[cfg_attr(published_docs, doc(cfg(feature = "experimental-threads")))]
12use godot_cell::blocking::{InaccessibleGuard, MutGuard, RefGuard};
13#[cfg(not(feature = "experimental-threads"))] #[cfg_attr(published_docs, doc(cfg(not(feature = "experimental-threads"))))]
14use godot_cell::panicking::{InaccessibleGuard, MutGuard, RefGuard};
15use godot_ffi::out;
16
17use crate::obj::script::ScriptInstance;
18use crate::obj::{AsDyn, BorrowedGd, Gd, GodotClass};
19
20/// Immutably/shared bound reference guard for a [`Gd`][crate::obj::Gd] smart pointer.
21///
22/// See [`Gd::bind`][crate::obj::Gd::bind] for usage.
23// GdRef could technically implement Clone, but it wasn't needed so far.
24#[derive(Debug)]
25pub struct GdRef<'a, T: GodotClass> {
26    guard: RefGuard<'a, T>,
27}
28
29impl<'a, T: GodotClass> GdRef<'a, T> {
30    pub(crate) fn from_guard(guard: RefGuard<'a, T>) -> Self {
31        crate::task::await_point_inc();
32        Self { guard }
33    }
34}
35
36impl<T: GodotClass> Deref for GdRef<'_, T> {
37    type Target = T;
38
39    fn deref(&self) -> &T {
40        &self.guard
41    }
42}
43
44impl<T: GodotClass> Drop for GdRef<'_, T> {
45    fn drop(&mut self) {
46        crate::task::await_point_dec();
47        out!("GdRef drop: {:?}", std::any::type_name::<T>());
48    }
49}
50
51// ----------------------------------------------------------------------------------------------------------------------------------------------
52
53/// Mutably/exclusively bound reference guard for a [`Gd`][crate::obj::Gd] smart pointer.
54///
55/// See [`Gd::bind_mut`][crate::obj::Gd::bind_mut] for usage.
56#[derive(Debug)]
57pub struct GdMut<'a, T: GodotClass> {
58    guard: MutGuard<'a, T>,
59}
60
61impl<'a, T: GodotClass> GdMut<'a, T> {
62    pub(crate) fn from_guard(guard: MutGuard<'a, T>) -> Self {
63        crate::task::await_point_inc();
64        Self { guard }
65    }
66}
67
68impl<T: GodotClass> Deref for GdMut<'_, T> {
69    type Target = T;
70
71    fn deref(&self) -> &T {
72        &self.guard
73    }
74}
75
76impl<T: GodotClass> DerefMut for GdMut<'_, T> {
77    fn deref_mut(&mut self) -> &mut T {
78        &mut self.guard
79    }
80}
81
82impl<T: GodotClass> Drop for GdMut<'_, T> {
83    fn drop(&mut self) {
84        crate::task::await_point_dec();
85        out!("GdMut drop: {:?}", std::any::type_name::<T>());
86    }
87}
88
89// ----------------------------------------------------------------------------------------------------------------------------------------------
90// Type-erased Gd guards
91
92trait ErasedGuard<'a>: 'a {}
93
94impl<'a, T: GodotClass> ErasedGuard<'a> for GdRef<'a, T> {}
95impl<'a, T: GodotClass> ErasedGuard<'a> for GdMut<'a, T> {}
96
97// ----------------------------------------------------------------------------------------------------------------------------------------------
98
99/// Shared reference guard for a [`DynGd`][crate::obj::DynGd] smart pointer.
100///
101/// Returned by [`DynGd::dyn_bind()`][crate::obj::DynGd::dyn_bind].
102pub struct DynGdRef<'a, D: ?Sized> {
103    /// Never accessed, but is kept alive to ensure dynamic borrow checks are upheld and the object isn't freed.
104    _guard: Box<dyn ErasedGuard<'a>>,
105    cached_ptr: *const D,
106}
107
108impl<'a, D> DynGdRef<'a, D>
109where
110    D: ?Sized + 'static,
111{
112    pub(crate) fn from_guard<T: AsDyn<D>>(guard: GdRef<'a, T>) -> Self {
113        let obj = &*guard;
114        let dyn_obj = obj.dyn_upcast();
115
116        // Note: this pointer is persisted because it is protected by the guard, and the original T instance is pinned during that.
117        // Caching prevents extra indirections; any calls through the dyn guard after the first is simply a Rust dyn-trait virtual call.
118        let cached_ptr = std::ptr::addr_of!(*dyn_obj);
119
120        Self {
121            _guard: Box::new(guard),
122            cached_ptr,
123        }
124    }
125}
126
127impl<D: ?Sized> Deref for DynGdRef<'_, D> {
128    type Target = D;
129
130    fn deref(&self) -> &D {
131        // SAFETY: pointer refers to object that is pinned while guard is alive.
132        unsafe { &*self.cached_ptr }
133    }
134}
135
136impl<D: ?Sized> Drop for DynGdRef<'_, D> {
137    fn drop(&mut self) {
138        out!("DynGdRef drop: {:?}", std::any::type_name::<D>());
139    }
140}
141
142// ----------------------------------------------------------------------------------------------------------------------------------------------
143
144/// Mutably/exclusively bound reference guard for a [`DynGd`][crate::obj::DynGd] smart pointer.
145///
146/// Returned by [`DynGd::dyn_bind_mut()`][crate::obj::DynGd::dyn_bind_mut].
147pub struct DynGdMut<'a, D: ?Sized> {
148    /// Never accessed, but is kept alive to ensure dynamic borrow checks are upheld and the object isn't freed.
149    _guard: Box<dyn ErasedGuard<'a>>,
150    cached_ptr: *mut D,
151}
152
153impl<'a, D> DynGdMut<'a, D>
154where
155    D: ?Sized + 'static,
156{
157    pub(crate) fn from_guard<T: AsDyn<D>>(mut guard: GdMut<'a, T>) -> Self {
158        let obj = &mut *guard;
159        let dyn_obj = obj.dyn_upcast_mut();
160
161        // Note: this pointer is persisted because it is protected by the guard, and the original T instance is pinned during that.
162        // Caching prevents extra indirections; any calls through the dyn guard after the first is simply a Rust dyn-trait virtual call.
163        let cached_ptr = std::ptr::addr_of_mut!(*dyn_obj);
164
165        Self {
166            _guard: Box::new(guard),
167            cached_ptr,
168        }
169    }
170}
171
172impl<D: ?Sized> Deref for DynGdMut<'_, D> {
173    type Target = D;
174
175    fn deref(&self) -> &D {
176        // SAFETY: pointer refers to object that is pinned while guard is alive.
177        unsafe { &*self.cached_ptr }
178    }
179}
180
181impl<D: ?Sized> DerefMut for DynGdMut<'_, D> {
182    fn deref_mut(&mut self) -> &mut D {
183        // SAFETY: pointer refers to object that is pinned while guard is alive.
184        unsafe { &mut *self.cached_ptr }
185    }
186}
187
188impl<D: ?Sized> Drop for DynGdMut<'_, D> {
189    fn drop(&mut self) {
190        out!("DynGdMut drop: {:?}", std::any::type_name::<D>());
191    }
192}
193
194// ----------------------------------------------------------------------------------------------------------------------------------------------
195
196macro_rules! make_base_ref {
197    ($ident:ident, $bound:ident, $doc_type:ident, $doc_path:path, $object_name:literal) => {
198        /// Shared reference guard for a [`Base`](crate::obj::Base) pointer.
199        ///
200        #[doc = concat!("This can be used to call methods on the base object of a ", $object_name, " that takes `&self` as the receiver.\n\n")]
201        #[doc = concat!("See [`", stringify!($doc_type), "::base()`](", stringify!($doc_path), "::base()) for usage.")]
202        pub struct $ident<'a, T: $bound> {
203            // The base() signature ties 'a to the instance borrow; no separate `&'a T` field needed.
204            borrowed_gd: BorrowedGd<'a, T::Base>,
205        }
206
207        impl<'a, T: $bound> $ident<'a, T> {
208            pub(crate) fn new(borrowed_gd: BorrowedGd<'a, T::Base>) -> Self {
209                Self { borrowed_gd }
210            }
211        }
212
213        impl<T: $bound> Deref for $ident<'_, T> {
214            type Target = Gd<T::Base>;
215
216            fn deref(&self) -> &Gd<T::Base> {
217                &self.borrowed_gd
218            }
219        }
220    };
221}
222
223// ----------------------------------------------------------------------------------------------------------------------------------------------
224
225macro_rules! make_base_mut {
226    ($ident:ident, $bound:ident, $doc_type:ident, $doc_path:path, $object_name:literal) => {
227        /// Mutable/exclusive reference guard for a [`Base`](crate::obj::Base) pointer.
228        ///
229        /// This can be used to call methods on the base object of a Rust object, which takes `&self` or `&mut self` as the receiver.
230        ///
231        #[doc = concat!("See [`", stringify!($doc_type), "::base_mut()`](", stringify!($doc_path), "::base_mut()) for usage.\n")]
232        pub struct $ident<'a, T: $bound> {
233            borrowed_gd: BorrowedGd<'a, T::Base>,
234            _inaccessible_guard: InaccessibleGuard<'a, T>,
235        }
236
237        impl<'a, T: $bound> $ident<'a, T> {
238            /// Both parameters share `'a`: a `BorrowedGd` constructed with an unbound lifetime (raw pointer) is thereby unified with the
239            /// guard's borrow of the instance, which keeps the base object alive.
240            pub(crate) fn new(
241                borrowed_gd: BorrowedGd<'a, T::Base>,
242                inaccessible_guard: InaccessibleGuard<'a, T>,
243            ) -> Self {
244                Self {
245                    borrowed_gd,
246                    _inaccessible_guard: inaccessible_guard,
247                }
248            }
249        }
250
251        impl<T: $bound> Deref for $ident<'_, T> {
252            type Target = Gd<T::Base>;
253
254            fn deref(&self) -> &Gd<T::Base> {
255                &self.borrowed_gd
256            }
257        }
258
259        impl<T: $bound> DerefMut for $ident<'_, T> {
260            fn deref_mut(&mut self) -> &mut Gd<T::Base> {
261                &mut self.borrowed_gd
262            }
263        }
264    };
265}
266
267make_base_ref!(
268    BaseRef,
269    GodotClass,
270    WithBaseField,
271    super::WithBaseField,
272    "Rust object"
273);
274make_base_mut!(
275    BaseMut,
276    GodotClass,
277    WithBaseField,
278    super::WithBaseField,
279    "Rust object"
280);
281
282make_base_ref!(
283    ScriptBaseRef,
284    ScriptInstance,
285    SiMut,
286    crate::obj::script::SiMut,
287    "[`ScriptInstance`]"
288);
289make_base_mut!(
290    ScriptBaseMut,
291    ScriptInstance,
292    SiMut,
293    crate::obj::script::SiMut,
294    "[`ScriptInstance`]"
295);