1use 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#[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#[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
85trait 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
93pub struct DynGdRef<'a, D: ?Sized> {
99 _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 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 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
139pub struct DynGdMut<'a, D: ?Sized> {
145 _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 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 unsafe { &*self.cached_ptr }
176 }
177}
178
179impl<D: ?Sized> DerefMut for DynGdMut<'_, D> {
180 fn deref_mut(&mut self) -> &mut D {
181 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
192macro_rules! make_base_ref {
195 ($ident:ident, $bound:ident, $doc_type:ident, $doc_path:path, $object_name:literal) => {
196 #[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
224macro_rules! make_base_mut {
227 ($ident:ident, $bound:ident, $doc_type:ident, $doc_path:path, $object_name:literal) => {
228 #[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);