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