rusteal_core/
object_ref.rs1use std::marker::PhantomData;
8use std::ops::Deref;
9
10use rusteal_ffi::{UClassHandle, UObjectHandle};
11
12use crate::error::{check_ffi, RustealError, RustealResult};
13use crate::ffi_dispatch;
14use crate::pinned::Pinned;
15use crate::traits::{HasParent, UeClass, UeHandle, ValidHandle};
16
17#[repr(transparent)]
24pub struct UObjectRef<T: UeClass> {
25 handle: UObjectHandle,
26 _marker: PhantomData<*const T>, }
28
29impl<T: UeClass> Clone for UObjectRef<T> {
32 fn clone(&self) -> Self {
33 *self
34 }
35}
36
37impl<T: UeClass> Copy for UObjectRef<T> {}
38
39impl<T: UeClass> PartialEq for UObjectRef<T> {
40 fn eq(&self, other: &Self) -> bool {
41 self.handle == other.handle
42 }
43}
44
45impl<T: UeClass> Eq for UObjectRef<T> {}
46
47impl<T: UeClass> std::hash::Hash for UObjectRef<T> {
48 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
49 self.handle.hash(state);
50 }
51}
52
53unsafe impl<T: UeClass> Send for UObjectRef<T> {}
56
57impl<T: UeClass> Default for UObjectRef<T> {
58 fn default() -> Self {
60 Self::null()
61 }
62}
63
64impl<T: UeClass> UObjectRef<T> {
65 #[inline]
67 pub fn null() -> Self {
68 UObjectRef {
69 handle: UObjectHandle::null(),
70 _marker: PhantomData,
71 }
72 }
73
74 #[inline]
80 pub unsafe fn from_raw(handle: UObjectHandle) -> Self {
81 UObjectRef {
82 handle,
83 _marker: PhantomData,
84 }
85 }
86
87 #[inline]
89 pub fn raw(&self) -> UObjectHandle {
90 self.handle
91 }
92
93 #[inline]
95 pub fn is_valid(&self) -> bool {
96 unsafe { ffi_dispatch::core_is_valid(self.handle) }
97 }
98
99 #[inline]
102 pub fn checked(&self) -> RustealResult<Checked<T>> {
103 if self.is_valid() {
104 Ok(Checked {
105 handle: self.handle,
106 _marker: PhantomData,
107 })
108 } else {
109 Err(RustealError::ObjectDestroyed)
110 }
111 }
112
113 pub fn cast<U: UeClass>(self) -> RustealResult<UObjectRef<U>> {
116 let h = self.checked()?.raw();
117 let target = U::static_class();
118 if unsafe { ffi_dispatch::core_is_a(h, target) } {
119 Ok(UObjectRef {
120 handle: self.handle,
121 _marker: PhantomData,
122 })
123 } else {
124 Err(RustealError::InvalidCast)
125 }
126 }
127
128 pub fn pin(self) -> RustealResult<Pinned<T>> {
130 Pinned::new(self)
131 }
132
133 pub fn get_name(&self) -> RustealResult<String> {
135 let h = self.checked()?.raw();
136 let mut buf = [0u8; 256];
138 let mut out_len: u32 = 0;
139 let code = unsafe {
140 ffi_dispatch::core_get_name(h, buf.as_mut_ptr(), buf.len() as u32, &mut out_len)
141 };
142 check_ffi(code)?;
143 std::str::from_utf8(&buf[..out_len as usize])
145 .map(|s| s.to_owned())
146 .map_err(|_| RustealError::Internal("name is not valid UTF-8".into()))
147 }
148
149 pub fn get_class(&self) -> RustealResult<UClassHandle> {
151 let h = self.checked()?.raw();
152 Ok(unsafe { ffi_dispatch::core_get_class(h) })
153 }
154
155 pub fn get_outer(&self) -> RustealResult<UObjectHandle> {
157 let h = self.checked()?.raw();
158 Ok(unsafe { ffi_dispatch::core_get_outer(h) })
159 }
160
161 #[inline]
164 pub fn is_a<U: UeClass>(&self) -> bool {
165 self.is_valid() && unsafe { ffi_dispatch::core_is_a(self.handle, U::static_class()) }
166 }
167}
168
169impl<T: HasParent> UObjectRef<T> {
170 #[inline]
172 pub fn upcast(self) -> UObjectRef<T::Parent> {
173 unsafe { UObjectRef::from_raw(self.handle) }
174 }
175}
176
177impl<T: UeClass> UObjectRef<T> {
178 #[inline]
181 pub fn upcast_to<U: UeClass>(self) -> UObjectRef<U>
182 where
183 T: crate::traits::Inherits<U>,
184 {
185 unsafe { UObjectRef::from_raw(self.handle) }
186 }
187}
188
189pub trait ObjectPointer: Sized {
193 unsafe fn from_object_handle(handle: UObjectHandle) -> Self;
199
200 fn object_handle(&self) -> UObjectHandle;
202}
203
204impl<T: UeClass> ObjectPointer for UObjectRef<T> {
205 #[inline]
206 unsafe fn from_object_handle(handle: UObjectHandle) -> Self {
207 unsafe { UObjectRef::from_raw(handle) }
208 }
209
210 #[inline]
211 fn object_handle(&self) -> UObjectHandle {
212 self.handle
213 }
214}
215
216impl<T: HasParent> Deref for UObjectRef<T> {
219 type Target = UObjectRef<T::Parent>;
220 #[inline]
221 fn deref(&self) -> &UObjectRef<T::Parent> {
222 unsafe { &*(self as *const _ as *const UObjectRef<T::Parent>) }
223 }
224}
225
226impl<T: UeClass> UeHandle for UObjectRef<T> {
227 #[inline]
228 fn checked_handle(&self) -> RustealResult<UObjectHandle> {
229 self.checked().map(|c| c.raw())
230 }
231
232 #[inline]
233 fn raw_handle(&self) -> UObjectHandle {
234 self.raw()
235 }
236}
237
238impl<T: UeClass> std::fmt::Debug for UObjectRef<T> {
239 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
240 f.debug_struct("UObjectRef")
241 .field("handle", &self.handle)
242 .field("valid", &self.is_valid())
243 .finish()
244 }
245}
246
247#[derive(Clone, Copy, PartialEq, Eq, Hash)]
257#[repr(transparent)]
258pub struct Checked<T: UeClass> {
259 handle: UObjectHandle,
260 _marker: PhantomData<*const T>,
261}
262
263unsafe impl<T: UeClass> Send for Checked<T> {}
264
265impl<T: UeClass> Checked<T> {
266 #[inline]
269 pub(crate) fn new_unchecked(handle: UObjectHandle) -> Self {
270 Checked {
271 handle,
272 _marker: PhantomData,
273 }
274 }
275
276 #[inline]
278 pub fn raw(&self) -> UObjectHandle {
279 self.handle
280 }
281
282 #[inline]
284 pub fn as_ref(&self) -> UObjectRef<T> {
285 unsafe { UObjectRef::from_raw(self.handle) }
286 }
287
288 #[inline]
291 pub fn is_a<U: UeClass>(&self) -> bool {
292 unsafe { ffi_dispatch::core_is_a(self.handle, U::static_class()) }
293 }
294
295 pub fn cast<U: UeClass>(self) -> RustealResult<Checked<U>> {
297 if self.is_a::<U>() {
298 Ok(Checked::new_unchecked(self.handle))
299 } else {
300 Err(RustealError::InvalidCast)
301 }
302 }
303}
304
305impl<T: HasParent> Checked<T> {
306 #[inline]
308 pub fn upcast(self) -> Checked<T::Parent> {
309 Checked::new_unchecked(self.handle)
310 }
311}
312
313impl<T: HasParent> Deref for Checked<T> {
316 type Target = Checked<T::Parent>;
317 #[inline]
318 fn deref(&self) -> &Checked<T::Parent> {
319 unsafe { &*(self as *const _ as *const Checked<T::Parent>) }
320 }
321}
322
323impl<T: UeClass> ValidHandle for Checked<T> {
324 #[inline]
325 fn handle(&self) -> UObjectHandle {
326 self.handle
327 }
328}
329
330impl<T: UeClass> std::fmt::Debug for Checked<T> {
331 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
332 f.debug_struct("Checked")
333 .field("handle", &self.handle)
334 .finish()
335 }
336}