Skip to main content

rusteal_core/
object_ref.rs

1use std::marker::PhantomData;
2use std::ops::Deref;
3use std::panic::Location;
4
5use rusteal_ffi::{UClassHandle, UObjectHandle};
6
7use crate::error::{RustealError, RustealResult};
8use crate::ffi_dispatch;
9use crate::pinned::Pinned;
10use crate::traits::{HasParent, UeClass, UeHandle, ValidHandle};
11
12#[repr(transparent)]
13pub struct UObjectRef<T: UeClass> {
14    handle: UObjectHandle,
15    _marker: PhantomData<*const T>,
16}
17
18impl<T: UeClass> Clone for UObjectRef<T> {
19    fn clone(&self) -> Self {
20        *self
21    }
22}
23
24impl<T: UeClass> Copy for UObjectRef<T> {}
25
26impl<T: UeClass> PartialEq for UObjectRef<T> {
27    fn eq(&self, other: &Self) -> bool {
28        self.handle == other.handle
29    }
30}
31
32impl<T: UeClass> Eq for UObjectRef<T> {}
33
34impl<T: UeClass> std::hash::Hash for UObjectRef<T> {
35    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
36        self.handle.hash(state);
37    }
38}
39
40unsafe impl<T: UeClass> Send for UObjectRef<T> {}
41
42impl<T: UeClass> Default for UObjectRef<T> {
43    fn default() -> Self {
44        Self::null()
45    }
46}
47
48impl<T: UeClass> UObjectRef<T> {
49    #[inline]
50    pub fn null() -> Self {
51        UObjectRef {
52            handle: UObjectHandle::null(),
53            _marker: PhantomData,
54        }
55    }
56
57    #[inline]
58    pub unsafe fn from_raw(handle: UObjectHandle) -> Self {
59        UObjectRef {
60            handle,
61            _marker: PhantomData,
62        }
63    }
64
65    #[inline]
66    pub fn raw(&self) -> UObjectHandle {
67        self.handle
68    }
69
70    #[inline]
71    pub fn is_valid(&self) -> bool {
72        unsafe { ffi_dispatch::core_is_valid(self.handle) }
73    }
74
75    #[inline]
76    #[track_caller]
77    pub fn checked(&self) -> RustealResult<Checked<T>> {
78        if self.is_valid() {
79            Ok(Checked {
80                handle: self.handle,
81                _marker: PhantomData,
82            })
83        } else {
84            Err(crate::error::destroyed::<T>(Location::caller()))
85        }
86    }
87
88    #[track_caller]
89    pub fn cast<U: UeClass>(self) -> RustealResult<UObjectRef<U>> {
90        let h = self.checked()?.raw();
91        let target = U::static_class();
92        if unsafe { ffi_dispatch::core_is_a(h, target) } {
93            Ok(UObjectRef {
94                handle: self.handle,
95                _marker: PhantomData,
96            })
97        } else {
98            Err(crate::error::cast_failed(h, target, Location::caller()))
99        }
100    }
101
102    #[track_caller]
103    pub fn pin(self) -> RustealResult<Pinned<T>> {
104        Pinned::new(self)
105    }
106
107    #[track_caller]
108    pub fn get_name(&self) -> RustealResult<String> {
109        let h = self.checked()?.raw();
110
111        crate::error::object_name(h).ok_or_else(|| RustealError::object_destroyed().on_handle(h))
112    }
113
114    #[track_caller]
115    pub fn get_class(&self) -> RustealResult<UClassHandle> {
116        let h = self.checked()?.raw();
117
118        Ok(unsafe { ffi_dispatch::core_get_class(h) })
119    }
120
121    #[track_caller]
122    pub fn get_outer(&self) -> RustealResult<UObjectHandle> {
123        let h = self.checked()?.raw();
124
125        Ok(unsafe { ffi_dispatch::core_get_outer(h) })
126    }
127
128    #[inline]
129    pub fn is_a<U: UeClass>(&self) -> bool {
130        self.is_valid() && unsafe { ffi_dispatch::core_is_a(self.handle, U::static_class()) }
131    }
132}
133
134impl<T: HasParent> UObjectRef<T> {
135    #[inline]
136    pub fn upcast(self) -> UObjectRef<T::Parent> {
137        unsafe { UObjectRef::from_raw(self.handle) }
138    }
139}
140
141impl<T: UeClass> UObjectRef<T> {
142    #[inline]
143    pub fn upcast_to<U: UeClass>(self) -> UObjectRef<U>
144    where
145        T: crate::traits::Inherits<U>,
146    {
147        unsafe { UObjectRef::from_raw(self.handle) }
148    }
149}
150
151pub trait ObjectPointer: Sized {
152    unsafe fn from_object_handle(handle: UObjectHandle) -> Self;
153
154    fn object_handle(&self) -> UObjectHandle;
155}
156
157impl<T: UeClass> ObjectPointer for UObjectRef<T> {
158    #[inline]
159    unsafe fn from_object_handle(handle: UObjectHandle) -> Self {
160        unsafe { UObjectRef::from_raw(handle) }
161    }
162
163    #[inline]
164    fn object_handle(&self) -> UObjectHandle {
165        self.handle
166    }
167}
168
169impl<T: HasParent> Deref for UObjectRef<T> {
170    type Target = UObjectRef<T::Parent>;
171    #[inline]
172    fn deref(&self) -> &UObjectRef<T::Parent> {
173        unsafe { &*(self as *const _ as *const UObjectRef<T::Parent>) }
174    }
175}
176
177impl<T: UeClass> UeHandle for UObjectRef<T> {
178    #[inline]
179    fn checked_handle(&self) -> RustealResult<UObjectHandle> {
180        self.checked().map(|c| c.raw())
181    }
182
183    #[inline]
184    fn raw_handle(&self) -> UObjectHandle {
185        self.raw()
186    }
187}
188
189impl<T: UeClass> std::fmt::Debug for UObjectRef<T> {
190    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
191        f.debug_struct("UObjectRef")
192            .field("handle", &self.handle)
193            .field("valid", &self.is_valid())
194            .finish()
195    }
196}
197
198#[derive(Clone, Copy, PartialEq, Eq, Hash)]
199#[repr(transparent)]
200pub struct Checked<T: UeClass> {
201    handle: UObjectHandle,
202    _marker: PhantomData<*const T>,
203}
204
205unsafe impl<T: UeClass> Send for Checked<T> {}
206
207impl<T: UeClass> Checked<T> {
208    #[inline]
209    pub(crate) fn new_unchecked(handle: UObjectHandle) -> Self {
210        Checked {
211            handle,
212            _marker: PhantomData,
213        }
214    }
215
216    #[inline]
217    pub fn raw(&self) -> UObjectHandle {
218        self.handle
219    }
220
221    #[inline]
222    pub fn as_ref(&self) -> UObjectRef<T> {
223        unsafe { UObjectRef::from_raw(self.handle) }
224    }
225
226    #[inline]
227    pub fn is_a<U: UeClass>(&self) -> bool {
228        unsafe { ffi_dispatch::core_is_a(self.handle, U::static_class()) }
229    }
230
231    #[track_caller]
232    pub fn cast<U: UeClass>(self) -> RustealResult<Checked<U>> {
233        if self.is_a::<U>() {
234            Ok(Checked::new_unchecked(self.handle))
235        } else {
236            Err(crate::error::cast_failed(
237                self.handle,
238                U::static_class(),
239                Location::caller(),
240            ))
241        }
242    }
243}
244
245impl<T: HasParent> Checked<T> {
246    #[inline]
247    pub fn upcast(self) -> Checked<T::Parent> {
248        Checked::new_unchecked(self.handle)
249    }
250}
251
252impl<T: HasParent> Deref for Checked<T> {
253    type Target = Checked<T::Parent>;
254    #[inline]
255    fn deref(&self) -> &Checked<T::Parent> {
256        unsafe { &*(self as *const _ as *const Checked<T::Parent>) }
257    }
258}
259
260impl<T: UeClass> ValidHandle for Checked<T> {
261    #[inline]
262    fn handle(&self) -> UObjectHandle {
263        self.handle
264    }
265}
266
267impl<T: UeClass> std::fmt::Debug for Checked<T> {
268    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
269        f.debug_struct("Checked")
270            .field("handle", &self.handle)
271            .finish()
272    }
273}