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::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}