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