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
8#[cfg(not(feature = "experimental-threads"))] #[cfg_attr(published_docs, doc(cfg(not(feature = "experimental-threads"))))]
9use godot_cell::panicking::{InaccessibleGuard, MutGuard, RefGuard};
10
11#[cfg(feature = "experimental-threads")] #[cfg_attr(published_docs, doc(cfg(feature = "experimental-threads")))]
12use godot_cell::blocking::{InaccessibleGuard, MutGuard, RefGuard};
13
14use godot_ffi::out;
15
16use std::fmt::Debug;
17use std::ops::{Deref, DerefMut};
18
19use crate::obj::script::ScriptInstance;
20use crate::obj::{AsDyn, Gd, GodotClass};
21
22/// Immutably/shared bound reference guard for a [`Gd`][crate::obj::Gd] smart pointer.
23///
24/// See [`Gd::bind`][crate::obj::Gd::bind] for usage.
25#[derive(Debug)]
26pub struct GdRef<'a, T: GodotClass> {
27    guard: RefGuard<'a, T>,
28}
29
30impl<'a, T: GodotClass> GdRef<'a, T> {
31    pub(crate) fn from_guard(guard: RefGuard<'a, T>) -> Self {
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        out!("GdRef drop: {:?}", std::any::type_name::<T>());
47    }
48}
49
50// TODO Clone or Share
51
52// ----------------------------------------------------------------------------------------------------------------------------------------------
53
54/// Mutably/exclusively bound reference guard for a [`Gd`][crate::obj::Gd] smart pointer.
55///
56/// See [`Gd::bind_mut`][crate::obj::Gd::bind_mut] for usage.
57#[derive(Debug)]
58pub struct GdMut<'a, T: GodotClass> {
59    guard: MutGuard<'a, T>,
60}
61
62impl<'a, T: GodotClass> GdMut<'a, T> {
63    pub(crate) fn from_guard(guard: MutGuard<'a, T>) -> Self {
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        out!("GdMut drop: {:?}", std::any::type_name::<T>());
85    }
86}
87
88// ----------------------------------------------------------------------------------------------------------------------------------------------
89// Type-erased Gd guards
90
91trait ErasedGuard<'a>: 'a {}
92
93impl<'a, T: GodotClass> ErasedGuard<'a> for GdRef<'a, T> {}
94impl<'a, T: GodotClass> ErasedGuard<'a> for GdMut<'a, T> {}
95
96// ----------------------------------------------------------------------------------------------------------------------------------------------
97
98/// Shared reference guard for a [`DynGd`][crate::obj::DynGd] smart pointer.
99///
100/// Returned by [`DynGd::dyn_bind()`][crate::obj::DynGd::dyn_bind].
101pub struct DynGdRef<'a, D: ?Sized> {
102    /// Never accessed, but is kept alive to ensure dynamic borrow checks are upheld and the object isn't freed.
103    _guard: Box<dyn ErasedGuard<'a>>,
104    cached_ptr: *const D,
105}
106
107impl<'a, D> DynGdRef<'a, D>
108where
109    D: ?Sized + 'static,
110{
111    #[doc(hidden)]
112    pub 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    #[doc(hidden)]
158    pub fn from_guard<T: AsDyn<D>>(mut guard: GdMut<'a, T>) -> Self {
159        let obj = &mut *guard;
160        let dyn_obj = obj.dyn_upcast_mut();
161
162        // Note: this pointer is persisted because it is protected by the guard, and the original T instance is pinned during that.
163        // Caching prevents extra indirections; any calls through the dyn guard after the first is simply a Rust dyn-trait virtual call.
164        let cached_ptr = std::ptr::addr_of_mut!(*dyn_obj);
165
166        Self {
167            _guard: Box::new(guard),
168            cached_ptr,
169        }
170    }
171}
172
173impl<D: ?Sized> Deref for DynGdMut<'_, D> {
174    type Target = D;
175
176    fn deref(&self) -> &D {
177        // SAFETY: pointer refers to object that is pinned while guard is alive.
178        unsafe { &*self.cached_ptr }
179    }
180}
181
182impl<D: ?Sized> DerefMut for DynGdMut<'_, D> {
183    fn deref_mut(&mut self) -> &mut D {
184        // SAFETY: pointer refers to object that is pinned while guard is alive.
185        unsafe { &mut *self.cached_ptr }
186    }
187}
188
189impl<D: ?Sized> Drop for DynGdMut<'_, D> {
190    fn drop(&mut self) {
191        out!("DynGdMut drop: {:?}", std::any::type_name::<D>());
192    }
193}
194
195// ----------------------------------------------------------------------------------------------------------------------------------------------
196
197macro_rules! make_base_ref {
198    ($ident:ident, $bound:ident, $doc_type:ident, $doc_path:path, $object_name:literal) => {
199        /// Shared reference guard for a [`Base`](crate::obj::Base) pointer.
200        ///
201        #[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")]
202        #[doc = concat!("See [`", stringify!($doc_type), "::base()`](", stringify!($doc_path), "::base()) for usage.")]
203        pub struct $ident<'a, T: $bound> {
204            gd: Gd<T::Base>,
205            _instance: &'a T,
206        }
207
208        impl<'a, T: $bound> $ident<'a, T> {
209            pub(crate) fn new(gd: Gd<T::Base>, instance: &'a T) -> Self {
210                Self {
211                    gd,
212                    _instance: instance,
213                }
214            }
215        }
216
217        impl<T: $bound> Deref for $ident<'_, T> {
218            type Target = Gd<T::Base>;
219
220            fn deref(&self) -> &Gd<T::Base> {
221                &self.gd
222            }
223        }
224    };
225}
226
227// ----------------------------------------------------------------------------------------------------------------------------------------------
228
229macro_rules! make_base_mut {
230    ($ident:ident, $bound:ident, $doc_type:ident, $doc_path:path, $object_name:literal) => {
231        /// Mutable/exclusive reference guard for a [`Base`](crate::obj::Base) pointer.
232        ///
233        /// This can be used to call methods on the base object of a Rust object, which takes `&self` or `&mut self` as the receiver.
234        ///
235        #[doc = concat!("See [`", stringify!($doc_type), "::base_mut()`](", stringify!($doc_path), "::base_mut()) for usage.\n")]
236        pub struct $ident<'a, T: $bound> {
237            gd: Gd<T::Base>,
238            _inaccessible_guard: InaccessibleGuard<'a, T>,
239        }
240
241        impl<'a, T: $bound> $ident<'a, T> {
242            pub(crate) fn new(
243                gd: Gd<T::Base>,
244                inaccessible_guard: InaccessibleGuard<'a, T>,
245            ) -> Self {
246                Self {
247                    gd,
248                    _inaccessible_guard: inaccessible_guard,
249                }
250            }
251        }
252
253        impl<T: $bound> Deref for $ident<'_, T> {
254            type Target = Gd<T::Base>;
255
256            fn deref(&self) -> &Gd<T::Base> {
257                &self.gd
258            }
259        }
260
261        impl<T: $bound> DerefMut for $ident<'_, T> {
262            fn deref_mut(&mut self) -> &mut Gd<T::Base> {
263                &mut self.gd
264            }
265        }
266    };
267}
268
269make_base_ref!(
270    BaseRef,
271    GodotClass,
272    WithBaseField,
273    super::WithBaseField,
274    "rust object"
275);
276make_base_mut!(
277    BaseMut,
278    GodotClass,
279    WithBaseField,
280    super::WithBaseField,
281    "rust object"
282);
283
284make_base_ref!(
285    ScriptBaseRef,
286    ScriptInstance,
287    SiMut,
288    crate::obj::script::SiMut,
289    "[`ScriptInstance`]"
290);
291make_base_mut!(
292    ScriptBaseMut,
293    ScriptInstance,
294    SiMut,
295    crate::obj::script::SiMut,
296    "['ScriptInstance']"
297);