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
138impl<T: HasParent> Deref for UObjectRef<T> {
141 type Target = UObjectRef<T::Parent>;
142 #[inline]
143 fn deref(&self) -> &UObjectRef<T::Parent> {
144 unsafe { &*(self as *const _ as *const UObjectRef<T::Parent>) }
145 }
146}
147
148impl<T: UeClass> UeHandle for UObjectRef<T> {
149 #[inline]
150 fn checked_handle(&self) -> RustealResult<UObjectHandle> {
151 self.checked().map(|c| c.raw())
152 }
153
154 #[inline]
155 fn raw_handle(&self) -> UObjectHandle {
156 self.raw()
157 }
158}
159
160impl<T: UeClass> std::fmt::Debug for UObjectRef<T> {
161 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
162 f.debug_struct("UObjectRef")
163 .field("handle", &self.handle)
164 .field("valid", &self.is_valid())
165 .finish()
166 }
167}
168
169#[derive(Clone, Copy, PartialEq, Eq, Hash)]
179#[repr(transparent)]
180pub struct Checked<T: UeClass> {
181 handle: UObjectHandle,
182 _marker: PhantomData<*const T>,
183}
184
185unsafe impl<T: UeClass> Send for Checked<T> {}
186
187impl<T: UeClass> Checked<T> {
188 #[inline]
191 pub(crate) fn new_unchecked(handle: UObjectHandle) -> Self {
192 Checked {
193 handle,
194 _marker: PhantomData,
195 }
196 }
197
198 #[inline]
200 pub fn raw(&self) -> UObjectHandle {
201 self.handle
202 }
203
204 #[inline]
206 pub fn as_ref(&self) -> UObjectRef<T> {
207 unsafe { UObjectRef::from_raw(self.handle) }
208 }
209
210 #[inline]
213 pub fn is_a<U: UeClass>(&self) -> bool {
214 unsafe { ffi_dispatch::core_is_a(self.handle, U::static_class()) }
215 }
216
217 pub fn cast<U: UeClass>(self) -> RustealResult<Checked<U>> {
219 if self.is_a::<U>() {
220 Ok(Checked::new_unchecked(self.handle))
221 } else {
222 Err(RustealError::InvalidCast)
223 }
224 }
225}
226
227impl<T: HasParent> Checked<T> {
228 #[inline]
230 pub fn upcast(self) -> Checked<T::Parent> {
231 Checked::new_unchecked(self.handle)
232 }
233}
234
235impl<T: HasParent> Deref for Checked<T> {
238 type Target = Checked<T::Parent>;
239 #[inline]
240 fn deref(&self) -> &Checked<T::Parent> {
241 unsafe { &*(self as *const _ as *const Checked<T::Parent>) }
242 }
243}
244
245impl<T: UeClass> ValidHandle for Checked<T> {
246 #[inline]
247 fn handle(&self) -> UObjectHandle {
248 self.handle
249 }
250}
251
252impl<T: UeClass> std::fmt::Debug for Checked<T> {
253 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
254 f.debug_struct("Checked")
255 .field("handle", &self.handle)
256 .finish()
257 }
258}