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 pub fn raw(&self) -> UClassHandle {
62 self.handle
63 }
64
65 pub fn is_null(&self) -> bool {
66 self.handle.is_null()
67 }
68}
69
70impl<T: HasParent> SubclassOf<T> {
71 #[inline]
72 pub fn upcast(self) -> SubclassOf<T::Parent> {
73 unsafe { SubclassOf::from_raw(self.handle) }
74 }
75}
76
77impl<T: UeClass> SubclassOf<T> {
78 #[inline]
79 pub fn upcast_to<U: UeClass>(self) -> SubclassOf<U>
80 where
81 T: crate::traits::Inherits<U>,
82 {
83 unsafe { SubclassOf::from_raw(self.handle) }
84 }
85}
86
87impl<T: UeClass> ObjectPointer for SubclassOf<T> {
88 #[inline]
89 unsafe fn from_object_handle(handle: UObjectHandle) -> Self {
90 unsafe { Self::from_raw(UClassHandle(handle.0)) }
91 }
92
93 #[inline]
94 fn object_handle(&self) -> UObjectHandle {
95 UObjectHandle(self.handle.0)
96 }
97}
98
99impl<T: UeClass> Default for SubclassOf<T> {
100 fn default() -> Self {
101 Self::null()
102 }
103}
104
105impl<T: UeClass> std::fmt::Debug for SubclassOf<T> {
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 f.debug_tuple("SubclassOf").field(&self.handle.0).finish()
108 }
109}
110
111unsafe impl<T: UeClass> ContainerElement for SubclassOf<T> {
112 const BUF_SIZE: u32 = std::mem::size_of::<UObjectHandle>() as u32;
113
114 #[inline]
115 unsafe fn read_from_buf(buf: *const u8, _written: u32) -> Self {
116 unsafe {
117 let handle = (buf as *const UObjectHandle).read_unaligned();
118
119 Self::from_raw(UClassHandle(handle.0))
120 }
121 }
122
123 #[inline]
124 unsafe fn write_to_buf(&self, buf: *mut u8) -> u32 {
125 unsafe {
126 (buf as *mut UObjectHandle).write_unaligned(UObjectHandle(self.handle.0));
127
128 std::mem::size_of::<UObjectHandle>() as u32
129 }
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use super::*;
136
137 struct Probe;
138 impl UeClass for Probe {
139 fn static_class() -> UClassHandle {
140 UClassHandle::from_addr(0x1000)
141 }
142 }
143
144 #[test]
145 fn compares_by_class() {
146 let base = SubclassOf::<Probe>::base();
147 assert_eq!(base, SubclassOf::<Probe>::base());
148 assert_ne!(base, SubclassOf::<Probe>::null());
149 assert!(SubclassOf::<Probe>::default().is_null());
150 assert_eq!(base.raw(), Probe::static_class());
151 }
152
153 struct Child;
154 impl UeClass for Child {
155 fn static_class() -> UClassHandle {
156 UClassHandle::from_addr(0x2000)
157 }
158 }
159 impl HasParent for Child {
160 type Parent = Probe;
161 }
162
163 #[test]
164 fn travels_as_an_object_pointer_and_upcasts() {
165 let child = SubclassOf::<Child>::base();
166 let handle = child.object_handle();
167 assert_eq!(handle.to_addr(), 0x2000);
168
169 assert_eq!(
170 unsafe { SubclassOf::<Child>::from_object_handle(handle) },
171 child
172 );
173
174 let as_parent: SubclassOf<Probe> = child.upcast();
175 assert_eq!(as_parent.raw(), Child::static_class());
176 }
177
178 #[test]
179 fn round_trips_through_a_container_buffer() {
180 let base = SubclassOf::<Probe>::base();
181 let mut buf = [0u8; 8];
182
183 unsafe {
184 assert_eq!(base.write_to_buf(buf.as_mut_ptr()), 8);
185 assert_eq!(SubclassOf::<Probe>::read_from_buf(buf.as_ptr(), 8), base);
186 }
187 }
188}