gdnative_core/object/
raw.rs1use std::fmt::{self, Debug};
2use std::marker::PhantomData;
3use std::ptr::{self, NonNull};
4
5use crate::core_types::GodotString;
6use crate::object::memory::RefCounted;
7use crate::private::get_api;
8use crate::sys;
9
10use super::GodotObject;
11
12#[repr(C)]
17pub struct RawObject<T> {
18 _opaque: [u8; 0],
19 _marker: PhantomData<(T, *const ())>,
20}
21
22impl<T: GodotObject> RawObject<T> {
23 #[inline]
30 pub unsafe fn from_sys_ref_unchecked<'a>(obj: NonNull<sys::godot_object>) -> &'a Self {
31 &*(obj.as_ptr() as *mut Self)
32 }
33
34 #[inline]
41 pub unsafe fn try_from_sys_ref<'a>(obj: NonNull<sys::godot_object>) -> Option<&'a Self> {
42 if ptr_is_class(obj.as_ptr(), T::class_name()) {
43 Some(Self::from_sys_ref_unchecked(obj))
44 } else {
45 None
46 }
47 }
48
49 #[inline]
51 pub fn sys(&self) -> NonNull<sys::godot_object> {
52 unsafe { NonNull::new_unchecked(self as *const _ as *mut _) }
54 }
55
56 #[inline]
58 pub fn is_class<U: GodotObject>(&self) -> bool {
59 self.is_class_by_name(U::class_name())
60 }
61
62 #[inline]
64 pub fn is_class_by_name(&self, class_name: &str) -> bool {
65 unsafe { ptr_is_class(self.sys().as_ptr(), class_name) }
66 }
67
68 #[inline]
70 pub fn class_name(&self) -> String {
71 let api = crate::private::get_api();
72 let get_class_method = crate::private::ObjectMethodTable::get(api).get_class;
73 let mut argument_buffer = [ptr::null() as *const libc::c_void; 0];
74 let mut class_name = sys::godot_string::default();
75 let ret_ptr = &mut class_name as *mut sys::godot_string;
76
77 unsafe {
78 (api.godot_method_bind_ptrcall)(
79 get_class_method,
80 self.sys().as_ptr(),
81 argument_buffer.as_mut_ptr() as *mut _,
82 ret_ptr as *mut _,
83 );
84 }
85
86 let string = GodotString::from_sys(class_name);
87 string.to_string()
88 }
89
90 #[inline]
92 pub fn cast<U>(&self) -> Option<&RawObject<U>>
93 where
94 U: GodotObject,
95 {
96 unsafe { RawObject::try_from_sys_ref(self.sys()) }
97 }
98
99 #[inline]
106 pub unsafe fn cast_unchecked<U>(&self) -> &RawObject<U>
107 where
108 U: GodotObject,
109 {
110 RawObject::from_sys_ref_unchecked(self.sys())
111 }
112
113 #[inline]
119 pub unsafe fn free(&self) {
120 (get_api().godot_object_destroy)(self.sys().as_ptr());
121 }
122}
123
124impl<T: GodotObject<Memory = RefCounted>> RawObject<T> {
125 #[inline]
127 pub fn add_ref(&self) {
128 let api = crate::private::get_api();
129 let addref_method = crate::private::ReferenceMethodTable::get(api).reference;
130 let mut argument_buffer = [ptr::null() as *const libc::c_void; 0];
131 let mut ok = false;
132 let ok_ptr = &mut ok as *mut bool;
133
134 unsafe {
135 (api.godot_method_bind_ptrcall)(
136 addref_method,
137 self.sys().as_ptr(),
138 argument_buffer.as_mut_ptr() as *mut _,
139 ok_ptr as *mut _,
140 );
141 }
142
143 debug_assert!(ok);
147 }
148
149 #[inline]
157 pub unsafe fn unref(&self) -> bool {
158 let api = crate::private::get_api();
159 let unref_method = crate::private::ReferenceMethodTable::get(api).unreference;
160
161 let mut argument_buffer = [ptr::null() as *const libc::c_void; 0];
162 let mut last_reference = false;
163 let ret_ptr = &mut last_reference as *mut bool;
164 (api.godot_method_bind_ptrcall)(
165 unref_method,
166 self.sys().as_ptr(),
167 argument_buffer.as_mut_ptr() as *mut _,
168 ret_ptr as *mut _,
169 );
170
171 last_reference
172 }
173
174 #[inline]
182 pub unsafe fn unref_and_free_if_last(&self) -> bool {
183 let last_reference = self.unref();
184
185 if last_reference {
186 self.free();
187 }
188
189 last_reference
190 }
191
192 #[inline]
198 pub unsafe fn init_ref_count(&self) {
199 let obj = self.sys().as_ptr();
200
201 let api = crate::private::get_api();
202 let init_method = crate::private::ReferenceMethodTable::get(api).init_ref;
203
204 let mut argument_buffer = [ptr::null() as *const libc::c_void; 0];
205 let mut ok = false;
206 let ret_ptr = &mut ok as *mut bool;
207 (api.godot_method_bind_ptrcall)(
208 init_method,
209 obj,
210 argument_buffer.as_mut_ptr() as *mut _,
211 ret_ptr as *mut _,
212 );
213
214 debug_assert!(ok);
215 }
216}
217
218impl<T: GodotObject> Debug for RawObject<T> {
219 #[inline]
220 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
221 write!(f, "{}({:p})", T::class_name(), self.sys())
222 }
223}
224
225#[inline]
231unsafe fn ptr_is_class(obj: *mut sys::godot_object, class_name: &str) -> bool {
232 let api = crate::private::get_api();
233 let method_bind = crate::private::ObjectMethodTable::get(api).is_class;
234
235 let mut class_name = (api.godot_string_chars_to_utf8_with_len)(
236 class_name.as_ptr() as *const _,
237 class_name.len() as _,
238 );
239
240 let mut argument_buffer = [ptr::null() as *const libc::c_void; 1];
241 argument_buffer[0] = (&class_name) as *const _ as *const _;
242
243 let mut ret = false;
244 let ret_ptr = &mut ret as *mut _;
245 (api.godot_method_bind_ptrcall)(
246 method_bind,
247 obj,
248 argument_buffer.as_mut_ptr() as *mut _,
249 ret_ptr as *mut _,
250 );
251
252 (api.godot_string_destroy)(&mut class_name);
253
254 ret
255}