uika_runtime/
object_ref.rs1use std::marker::PhantomData;
8
9use uika_ffi::{UClassHandle, UObjectHandle};
10
11use crate::api::api;
12use crate::error::{check_ffi, UikaError, UikaResult};
13use crate::pinned::Pinned;
14use crate::traits::{UeClass, UeHandle, ValidHandle};
15
16#[derive(Clone, Copy, PartialEq, Eq, Hash)]
23#[repr(transparent)]
24pub struct UObjectRef<T: UeClass> {
25 handle: UObjectHandle,
26 _marker: PhantomData<*const T>, }
28
29unsafe impl<T: UeClass> Send for UObjectRef<T> {}
32
33impl<T: UeClass> UObjectRef<T> {
34 #[inline]
40 pub unsafe fn from_raw(handle: UObjectHandle) -> Self {
41 UObjectRef {
42 handle,
43 _marker: PhantomData,
44 }
45 }
46
47 #[inline]
49 pub fn raw(&self) -> UObjectHandle {
50 self.handle
51 }
52
53 #[inline]
55 pub fn is_valid(&self) -> bool {
56 unsafe { ((*api().core).is_valid)(self.handle) }
57 }
58
59 #[inline]
62 pub fn checked(&self) -> UikaResult<Checked<T>> {
63 if self.is_valid() {
64 Ok(Checked {
65 handle: self.handle,
66 _marker: PhantomData,
67 })
68 } else {
69 Err(UikaError::ObjectDestroyed)
70 }
71 }
72
73 pub fn cast<U: UeClass>(self) -> UikaResult<UObjectRef<U>> {
76 let h = self.checked()?.raw();
77 let target = U::static_class();
78 if unsafe { ((*api().core).is_a)(h, target) } {
79 Ok(UObjectRef {
80 handle: self.handle,
81 _marker: PhantomData,
82 })
83 } else {
84 Err(UikaError::InvalidCast)
85 }
86 }
87
88 pub fn pin(self) -> UikaResult<Pinned<T>> {
90 Pinned::new(self)
91 }
92
93 pub fn get_name(&self) -> UikaResult<String> {
95 let h = self.checked()?.raw();
96 let mut buf = [0u8; 256];
98 let mut out_len: u32 = 0;
99 let code = unsafe {
100 ((*api().core).get_name)(h, buf.as_mut_ptr(), buf.len() as u32, &mut out_len)
101 };
102 check_ffi(code)?;
103 std::str::from_utf8(&buf[..out_len as usize])
105 .map(|s| s.to_owned())
106 .map_err(|_| UikaError::Internal("name is not valid UTF-8".into()))
107 }
108
109 pub fn get_class(&self) -> UikaResult<UClassHandle> {
111 let h = self.checked()?.raw();
112 Ok(unsafe { ((*api().core).get_class)(h) })
113 }
114
115 pub fn get_outer(&self) -> UikaResult<UObjectHandle> {
117 let h = self.checked()?.raw();
118 Ok(unsafe { ((*api().core).get_outer)(h) })
119 }
120}
121
122impl<T: UeClass> UeHandle for UObjectRef<T> {
123 #[inline]
124 fn checked_handle(&self) -> UikaResult<UObjectHandle> {
125 self.checked().map(|c| c.raw())
126 }
127
128 #[inline]
129 fn raw_handle(&self) -> UObjectHandle {
130 self.raw()
131 }
132}
133
134impl<T: UeClass> std::fmt::Debug for UObjectRef<T> {
135 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
136 f.debug_struct("UObjectRef")
137 .field("handle", &self.handle)
138 .field("valid", &self.is_valid())
139 .finish()
140 }
141}
142
143#[derive(Clone, Copy, PartialEq, Eq, Hash)]
153#[repr(transparent)]
154pub struct Checked<T: UeClass> {
155 handle: UObjectHandle,
156 _marker: PhantomData<*const T>,
157}
158
159unsafe impl<T: UeClass> Send for Checked<T> {}
160
161impl<T: UeClass> Checked<T> {
162 #[inline]
165 pub(crate) fn new_unchecked(handle: UObjectHandle) -> Self {
166 Checked {
167 handle,
168 _marker: PhantomData,
169 }
170 }
171
172 #[inline]
174 pub fn raw(&self) -> UObjectHandle {
175 self.handle
176 }
177
178 #[inline]
180 pub fn as_ref(&self) -> UObjectRef<T> {
181 unsafe { UObjectRef::from_raw(self.handle) }
182 }
183}
184
185impl<T: UeClass> ValidHandle for Checked<T> {
186 #[inline]
187 fn handle(&self) -> UObjectHandle {
188 self.handle
189 }
190}
191
192impl<T: UeClass> std::fmt::Debug for Checked<T> {
193 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
194 f.debug_struct("Checked")
195 .field("handle", &self.handle)
196 .finish()
197 }
198}