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