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, Gd, GodotClass, PassiveGd};
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        Self { guard }
32    }
33}
34
35impl<T: GodotClass> Deref for GdRef<'_, T> {
36    type Target = T;
37
38    fn deref(&self) -> &T {
39        &self.guard
40    }
41}
42
43impl<T: GodotClass> Drop for GdRef<'_, T> {
44    fn drop(&mut self) {
45        out!("GdRef drop: {:?}", std::any::type_name::<T>());
46    }
47}
48
49// ----------------------------------------------------------------------------------------------------------------------------------------------
50
51/// Mutably/exclusively bound reference guard for a [`Gd`][crate::obj::Gd] smart pointer.
52///
53/// See [`Gd::bind_mut`][crate::obj::Gd::bind_mut] for usage.
54#[derive(Debug)]
55pub struct GdMut<'a, T: GodotClass> {
56    guard: MutGuard<'a, T>,
57}
58
59impl<'a, T: GodotClass> GdMut<'a, T> {
60    pub(crate) fn from_guard(guard: MutGuard<'a, T>) -> Self {
61        Self { guard }
62    }
63}
64
65impl<T: GodotClass> Deref for GdMut<'_, T> {
66    type Target = T;
67
68    fn deref(&self) -> &T {
69        &self.guard
70    }
71}
72
73impl<T: GodotClass> DerefMut for GdMut<'_, T> {
74    fn deref_mut(&mut self) -> &mut T {
75        &mut self.guard
76    }
77}
78
79impl<T: GodotClass> Drop for GdMut<'_, T> {
80    fn drop(&mut self) {
81        out!("GdMut drop: {:?}", std::any::type_name::<T>());
82    }
83}
84
85// ----------------------------------------------------------------------------------------------------------------------------------------------
86// Type-erased Gd guards
87
88trait ErasedGuard<'a>: 'a {}
89
90impl<'a, T: GodotClass> ErasedGuard<'a> for GdRef<'a, T> {}
91impl<'a, T: GodotClass> ErasedGuard<'a> for GdMut<'a, T> {}
92
93// ----------------------------------------------------------------------------------------------------------------------------------------------
94
95/// Shared reference guard for a [`DynGd`][crate::obj::DynGd] smart pointer.
96///
97/// Returned by [`DynGd::dyn_bind()`][crate::obj::DynGd::dyn_bind].
98pub struct DynGdRef<'a, D: ?Sized> {
99    /// Never accessed, but is kept alive to ensure dynamic borrow checks are upheld and the object isn't freed.
100    _guard: Box<dyn ErasedGuard<'a>>,
101    cached_ptr: *const D,
102}
103
104impl<'a, D> DynGdRef<'a, D>
105where
106    D: ?Sized + 'static,
107{
108    #[doc(hidden)]
109    pub fn from_guard<T: AsDyn<D>>(guard: GdRef<'a, T>) -> Self {
110        let obj = &*guard;
111        let dyn_obj = obj.dyn_upcast();
112
113        // Note: this pointer is persisted because it is protected by the guard, and the original T instance is pinned during that.
114        // Caching prevents extra indirections; any calls through the dyn guard after the first is simply a Rust dyn-trait virtual call.
115        let cached_ptr = std::ptr::addr_of!(*dyn_obj);
116
117        Self {
118            _guard: Box::new(guard),
119            cached_ptr,
120        }
121    }
122}
123
124impl<D: ?Sized> Deref for DynGdRef<'_, D> {
125    type Target = D;
126
127    fn deref(&self) -> &D {
128        // SAFETY: pointer refers to object that is pinned while guard is alive.
129        unsafe { &*self.cached_ptr }
130    }
131}
132
133impl<D: ?Sized> Drop for DynGdRef<'_, D> {
134    fn drop(&mut self) {
135        out!("DynGdRef drop: {:?}", std::any::type_name::<D>());
136    }
137}
138
139// ----------------------------------------------------------------------------------------------------------------------------------------------
140
141/// Mutably/exclusively bound reference guard for a [`DynGd`][crate::obj::DynGd] smart pointer.
142///
143/// Returned by [`DynGd::dyn_bind_mut()`][crate::obj::DynGd::dyn_bind_mut].
144pub struct DynGdMut<'a, D: ?Sized> {
145    /// Never accessed, but is kept alive to ensure dynamic borrow checks are upheld and the object isn't freed.
146    _guard: Box<dyn ErasedGuard<'a>>,
147    cached_ptr: *mut D,
148}
149
150impl<'a, D> DynGdMut<'a, D>
151where
152    D: ?Sized + 'static,
153{
154    #[doc(hidden)]
155    pub fn from_guard<T: AsDyn<D>>(mut guard: GdMut<'a, T>) -> Self {
156        let obj = &mut *guard;
157        let dyn_obj = obj.dyn_upcast_mut();
158
159        // Note: this pointer is persisted because it is protected by the guard, and the original T instance is pinned during that.
160        // Caching prevents extra indirections; any calls through the dyn guard after the first is simply a Rust dyn-trait virtual call.
161        let cached_ptr = std::ptr::addr_of_mut!(*dyn_obj);
162
163        Self {
164            _guard: Box::new(guard),
165            cached_ptr,
166        }
167    }
168}
169
170impl<D: ?Sized> Deref for DynGdMut<'_, D> {
171    type Target = D;
172
173    fn deref(&self) -> &D {
174        // SAFETY: pointer refers to object that is pinned while guard is alive.
175        unsafe { &*self.cached_ptr }
176    }
177}
178
179impl<D: ?Sized> DerefMut for DynGdMut<'_, D> {
180    fn deref_mut(&mut self) -> &mut D {
181        // SAFETY: pointer refers to object that is pinned while guard is alive.
182        unsafe { &mut *self.cached_ptr }
183    }
184}
185
186impl<D: ?Sized> Drop for DynGdMut<'_, D> {
187    fn drop(&mut self) {
188        out!("DynGdMut drop: {:?}", std::any::type_name::<D>());
189    }
190}
191
192// ----------------------------------------------------------------------------------------------------------------------------------------------
193
194macro_rules! make_base_ref {
195    ($ident:ident, $bound:ident, $doc_type:ident, $doc_path:path, $object_name:literal) => {
196        /// Shared reference guard for a [`Base`](crate::obj::Base) pointer.
197        ///
198        #[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")]
199        #[doc = concat!("See [`", stringify!($doc_type), "::base()`](", stringify!($doc_path), "::base()) for usage.")]
200        pub struct $ident<'a, T: $bound> {
201            passive_gd: PassiveGd<T::Base>,
202            _instance: &'a T,
203        }
204
205        impl<'a, T: $bound> $ident<'a, T> {
206            pub(crate) fn new(passive_gd: PassiveGd<T::Base>, instance: &'a T) -> Self {
207                Self {
208                    passive_gd,
209                    _instance: instance,
210                }
211            }
212        }
213
214        impl<T: $bound> Deref for $ident<'_, T> {
215            type Target = Gd<T::Base>;
216
217            fn deref(&self) -> &Gd<T::Base> {
218                &self.passive_gd
219            }
220        }
221    };
222}
223
224// ----------------------------------------------------------------------------------------------------------------------------------------------
225
226macro_rules! make_base_mut {
227    ($ident:ident, $bound:ident, $doc_type:ident, $doc_path:path, $object_name:literal) => {
228        /// Mutable/exclusive reference guard for a [`Base`](crate::obj::Base) pointer.
229        ///
230        /// This can be used to call methods on the base object of a Rust object, which takes `&self` or `&mut self` as the receiver.
231        ///
232        #[doc = concat!("See [`", stringify!($doc_type), "::base_mut()`](", stringify!($doc_path), "::base_mut()) for usage.\n")]
233        pub struct $ident<'a, T: $bound> {
234            passive_gd: PassiveGd<T::Base>,
235            _inaccessible_guard: InaccessibleGuard<'a, T>,
236        }
237
238        impl<'a, T: $bound> $ident<'a, T> {
239            pub(crate) fn new(
240                passive_gd: PassiveGd<T::Base>,
241                inaccessible_guard: InaccessibleGuard<'a, T>,
242            ) -> Self {
243                Self {
244                    passive_gd,
245                    _inaccessible_guard: inaccessible_guard,
246                }
247            }
248        }
249
250        impl<T: $bound> Deref for $ident<'_, T> {
251            type Target = Gd<T::Base>;
252
253            fn deref(&self) -> &Gd<T::Base> {
254                &self.passive_gd
255            }
256        }
257
258        impl<T: $bound> DerefMut for $ident<'_, T> {
259            fn deref_mut(&mut self) -> &mut Gd<T::Base> {
260                &mut self.passive_gd
261            }
262        }
263    };
264}
265
266make_base_ref!(
267    BaseRef,
268    GodotClass,
269    WithBaseField,
270    super::WithBaseField,
271    "rust object"
272);
273make_base_mut!(
274    BaseMut,
275    GodotClass,
276    WithBaseField,
277    super::WithBaseField,
278    "rust object"
279);
280
281make_base_ref!(
282    ScriptBaseRef,
283    ScriptInstance,
284    SiMut,
285    crate::obj::script::SiMut,
286    "[`ScriptInstance`]"
287);
288make_base_mut!(
289    ScriptBaseMut,
290    ScriptInstance,
291    SiMut,
292    crate::obj::script::SiMut,
293    "['ScriptInstance']"
294);