rusteal_core/
subclass_of.rs1use std::marker::PhantomData;
2
3use rusteal_ffi::{UClassHandle, UObjectHandle};
4
5use crate::containers::ContainerElement;
6use crate::object_ref::ObjectPointer;
7use crate::traits::{HasParent, UeClass};
8
9#[repr(transparent)]
10pub struct SubclassOf<T: UeClass> {
11 handle: UClassHandle,
12 _marker: PhantomData<*const T>,
13}
14
15impl<T: UeClass> Clone for SubclassOf<T> {
16 fn clone(&self) -> Self {
17 *self
18 }
19}
20
21impl<T: UeClass> Copy for SubclassOf<T> {}
22
23impl<T: UeClass> PartialEq for SubclassOf<T> {
24 fn eq(&self, other: &Self) -> bool {
25 self.handle == other.handle
26 }
27}
28
29impl<T: UeClass> Eq for SubclassOf<T> {}
30
31impl<T: UeClass> std::hash::Hash for SubclassOf<T> {
32 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
33 self.handle.hash(state);
34 }
35}
36
37unsafe impl<T: UeClass> Send for SubclassOf<T> {}
38
39impl<T: UeClass> SubclassOf<T> {
40 pub fn null() -> Self {
41 Self {
42 handle: UClassHandle::null(),
43 _marker: PhantomData,
44 }
45 }
46
47 pub fn base() -> Self {
48 Self {
49 handle: T::static_class(),
50 _marker: PhantomData,
51 }
52 }
53
54 pub unsafe fn from_raw(handle: UClassHandle) -> Self {
55 Self {
56 handle,
57 _marker: PhantomData,
58 }
59 }
60
61 #[track_caller]
62 pub fn from_class(class: UClassHandle) -> crate::error::RustealResult<Self> {
63 use crate::error::RustealError;
64
65 if class.is_null() {
66 return Err(RustealError::null_argument());
67 }
68
69 if !unsafe { crate::ffi_dispatch::core_is_child_of(class, T::static_class()) } {
70 return Err(RustealError::invalid_cast_to(
71 UObjectHandle(class.0),
72 T::static_class(),
73 ));
74 }
75
76 Ok(unsafe { Self::from_raw(class) })
77 }
78
79 pub fn raw(&self) -> UClassHandle {
80 self.handle
81 }
82
83 pub fn is_null(&self) -> bool {
84 self.handle.is_null()
85 }
86}
87
88impl<T: HasParent> SubclassOf<T> {
89 #[inline]
90 pub fn upcast(self) -> SubclassOf<T::Parent> {
91 unsafe { SubclassOf::from_raw(self.handle) }
92 }
93}
94
95impl<T: UeClass> SubclassOf<T> {
96 #[inline]
97 pub fn upcast_to<U: UeClass>(self) -> SubclassOf<U>
98 where
99 T: crate::traits::Inherits<U>,
100 {
101 unsafe { SubclassOf::from_raw(self.handle) }
102 }
103}
104
105impl<T: UeClass> ObjectPointer for SubclassOf<T> {
106 #[inline]
107 unsafe fn from_object_handle(handle: UObjectHandle) -> Self {
108 unsafe { Self::from_raw(UClassHandle(handle.0)) }
109 }
110
111 #[inline]
112 fn object_handle(&self) -> UObjectHandle {
113 UObjectHandle(self.handle.0)
114 }
115}
116
117impl<T: UeClass> Default for SubclassOf<T> {
118 fn default() -> Self {
119 Self::null()
120 }
121}
122
123impl<T: UeClass> std::fmt::Debug for SubclassOf<T> {
124 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
125 f.debug_tuple("SubclassOf").field(&self.handle.0).finish()
126 }
127}
128
129unsafe impl<T: UeClass> ContainerElement for SubclassOf<T> {
130 const BUF_SIZE: u32 = std::mem::size_of::<UObjectHandle>() as u32;
131
132 #[inline]
133 unsafe fn read_from_buf(buf: *const u8, _written: u32) -> Self {
134 unsafe {
135 let handle = (buf as *const UObjectHandle).read_unaligned();
136
137 Self::from_raw(UClassHandle(handle.0))
138 }
139 }
140
141 #[inline]
142 unsafe fn write_to_buf(&self, buf: *mut u8) -> u32 {
143 unsafe {
144 (buf as *mut UObjectHandle).write_unaligned(UObjectHandle(self.handle.0));
145
146 std::mem::size_of::<UObjectHandle>() as u32
147 }
148 }
149}
150
151#[cfg(test)]
152mod tests {
153 use super::*;
154
155 struct Probe;
156 impl UeClass for Probe {
157 fn static_class() -> UClassHandle {
158 UClassHandle::from_addr(0x1000)
159 }
160 }
161
162 #[test]
163 fn compares_by_class() {
164 let base = SubclassOf::<Probe>::base();
165 assert_eq!(base, SubclassOf::<Probe>::base());
166 assert_ne!(base, SubclassOf::<Probe>::null());
167 assert!(SubclassOf::<Probe>::default().is_null());
168 assert_eq!(base.raw(), Probe::static_class());
169 }
170
171 struct Child;
172 impl UeClass for Child {
173 fn static_class() -> UClassHandle {
174 UClassHandle::from_addr(0x2000)
175 }
176 }
177 impl HasParent for Child {
178 type Parent = Probe;
179 }
180
181 #[test]
182 fn travels_as_an_object_pointer_and_upcasts() {
183 let child = SubclassOf::<Child>::base();
184 let handle = child.object_handle();
185 assert_eq!(handle.to_addr(), 0x2000);
186
187 assert_eq!(
188 unsafe { SubclassOf::<Child>::from_object_handle(handle) },
189 child
190 );
191
192 let as_parent: SubclassOf<Probe> = child.upcast();
193 assert_eq!(as_parent.raw(), Child::static_class());
194 }
195
196 #[test]
197 fn round_trips_through_a_container_buffer() {
198 let base = SubclassOf::<Probe>::base();
199 let mut buf = [0u8; 8];
200
201 unsafe {
202 assert_eq!(base.write_to_buf(buf.as_mut_ptr()), 8);
203 assert_eq!(SubclassOf::<Probe>::read_from_buf(buf.as_ptr(), 8), base);
204 }
205 }
206}