rusteal_core/
object_ref.rs1use 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}