Skip to main content

rusteal_core/
object_ref.rs

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