rusteal_core/
object_ref.rs1use std::marker::PhantomData;
8use std::ops::Deref;
9
10use rusteal_ffi::{UClassHandle, UObjectHandle};
11
12use crate::error::{check_ffi, RustealError, RustealResult};
13use crate::ffi_dispatch;
14use crate::pinned::Pinned;
15use crate::traits::{HasParent, UeClass, UeHandle, ValidHandle};
16
17#[derive(Clone, Copy, PartialEq, Eq, Hash)]
24#[repr(transparent)]
25pub struct UObjectRef<T: UeClass> {
26 handle: UObjectHandle,
27 _marker: PhantomData<*const T>, }
29
30unsafe impl<T: UeClass> Send for UObjectRef<T> {}
33
34impl<T: UeClass> UObjectRef<T> {
35 #[inline]
41 pub unsafe fn from_raw(handle: UObjectHandle) -> Self {
42 UObjectRef {
43 handle,
44 _marker: PhantomData,
45 }
46 }
47
48 #[inline]
50 pub fn raw(&self) -> UObjectHandle {
51 self.handle
52 }
53
54 #[inline]
56 pub fn is_valid(&self) -> bool {
57 unsafe { ffi_dispatch::core_is_valid(self.handle) }
58 }
59
60 #[inline]
63 pub fn checked(&self) -> RustealResult<Checked<T>> {
64 if self.is_valid() {
65 Ok(Checked {
66 handle: self.handle,
67 _marker: PhantomData,
68 })
69 } else {
70 Err(RustealError::ObjectDestroyed)
71 }
72 }
73
74 pub fn cast<U: UeClass>(self) -> RustealResult<UObjectRef<U>> {
77 let h = self.checked()?.raw();
78 let target = U::static_class();
79 if unsafe { ffi_dispatch::core_is_a(h, target) } {
80 Ok(UObjectRef {
81 handle: self.handle,
82 _marker: PhantomData,
83 })
84 } else {
85 Err(RustealError::InvalidCast)
86 }
87 }
88
89 pub fn pin(self) -> RustealResult<Pinned<T>> {
91 Pinned::new(self)
92 }
93
94 pub fn get_name(&self) -> RustealResult<String> {
96 let h = self.checked()?.raw();
97 let mut buf = [0u8; 256];
99 let mut out_len: u32 = 0;
100 let code = unsafe {
101 ffi_dispatch::core_get_name(h, buf.as_mut_ptr(), buf.len() as u32, &mut out_len)
102 };
103 check_ffi(code)?;
104 std::str::from_utf8(&buf[..out_len as usize])
106 .map(|s| s.to_owned())
107 .map_err(|_| RustealError::Internal("name is not valid UTF-8".into()))
108 }
109
110 pub fn get_class(&self) -> RustealResult<UClassHandle> {
112 let h = self.checked()?.raw();
113 Ok(unsafe { ffi_dispatch::core_get_class(h) })
114 }
115
116 pub fn get_outer(&self) -> RustealResult<UObjectHandle> {
118 let h = self.checked()?.raw();
119 Ok(unsafe { ffi_dispatch::core_get_outer(h) })
120 }
121
122 #[inline]
125 pub fn is_a<U: UeClass>(&self) -> bool {
126 self.is_valid() && unsafe { ffi_dispatch::core_is_a(self.handle, U::static_class()) }
127 }
128}
129
130impl<T: HasParent> UObjectRef<T> {
131 #[inline]
133 pub fn upcast(self) -> UObjectRef<T::Parent> {
134 unsafe { UObjectRef::from_raw(self.handle) }
135 }
136}
137
138pub trait ObjectPointer: Sized {
142 unsafe fn from_object_handle(handle: UObjectHandle) -> Self;
148
149 fn object_handle(&self) -> UObjectHandle;
151}
152
153impl<T: UeClass> ObjectPointer for UObjectRef<T> {
154 #[inline]
155 unsafe fn from_object_handle(handle: UObjectHandle) -> Self {
156 unsafe { UObjectRef::from_raw(handle) }
157 }
158
159 #[inline]
160 fn object_handle(&self) -> UObjectHandle {
161 self.handle
162 }
163}
164
165impl<T: HasParent> Deref for UObjectRef<T> {
168 type Target = UObjectRef<T::Parent>;
169 #[inline]
170 fn deref(&self) -> &UObjectRef<T::Parent> {
171 unsafe { &*(self as *const _ as *const UObjectRef<T::Parent>) }
172 }
173}
174
175impl<T: UeClass> UeHandle for UObjectRef<T> {
176 #[inline]
177 fn checked_handle(&self) -> RustealResult<UObjectHandle> {
178 self.checked().map(|c| c.raw())
179 }
180
181 #[inline]
182 fn raw_handle(&self) -> UObjectHandle {
183 self.raw()
184 }
185}
186
187impl<T: UeClass> std::fmt::Debug for UObjectRef<T> {
188 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
189 f.debug_struct("UObjectRef")
190 .field("handle", &self.handle)
191 .field("valid", &self.is_valid())
192 .finish()
193 }
194}
195
196#[derive(Clone, Copy, PartialEq, Eq, Hash)]
206#[repr(transparent)]
207pub struct Checked<T: UeClass> {
208 handle: UObjectHandle,
209 _marker: PhantomData<*const T>,
210}
211
212unsafe impl<T: UeClass> Send for Checked<T> {}
213
214impl<T: UeClass> Checked<T> {
215 #[inline]
218 pub(crate) fn new_unchecked(handle: UObjectHandle) -> Self {
219 Checked {
220 handle,
221 _marker: PhantomData,
222 }
223 }
224
225 #[inline]
227 pub fn raw(&self) -> UObjectHandle {
228 self.handle
229 }
230
231 #[inline]
233 pub fn as_ref(&self) -> UObjectRef<T> {
234 unsafe { UObjectRef::from_raw(self.handle) }
235 }
236
237 #[inline]
240 pub fn is_a<U: UeClass>(&self) -> bool {
241 unsafe { ffi_dispatch::core_is_a(self.handle, U::static_class()) }
242 }
243
244 pub fn cast<U: UeClass>(self) -> RustealResult<Checked<U>> {
246 if self.is_a::<U>() {
247 Ok(Checked::new_unchecked(self.handle))
248 } else {
249 Err(RustealError::InvalidCast)
250 }
251 }
252}
253
254impl<T: HasParent> Checked<T> {
255 #[inline]
257 pub fn upcast(self) -> Checked<T::Parent> {
258 Checked::new_unchecked(self.handle)
259 }
260}
261
262impl<T: HasParent> Deref for Checked<T> {
265 type Target = Checked<T::Parent>;
266 #[inline]
267 fn deref(&self) -> &Checked<T::Parent> {
268 unsafe { &*(self as *const _ as *const Checked<T::Parent>) }
269 }
270}
271
272impl<T: UeClass> ValidHandle for Checked<T> {
273 #[inline]
274 fn handle(&self) -> UObjectHandle {
275 self.handle
276 }
277}
278
279impl<T: UeClass> std::fmt::Debug for Checked<T> {
280 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
281 f.debug_struct("Checked")
282 .field("handle", &self.handle)
283 .finish()
284 }
285}