commonlibsse_ng\re\b/
BSExtraData.rs1use crate::re::CxxVirtClass;
2use crate::re::ExtraDataType::ExtraDataType;
3use crate::re::offsets_rtti::RTTI_BSExtraData;
4use crate::re::offsets_vtable::VTABLE_BSExtraData;
5use crate::rel::ResolvableAddress as _;
6use crate::rel::id::VariantID;
7use core::ffi::c_void;
8use core::marker::PhantomData;
9use core::ptr::{self, NonNull};
10
11#[repr(C)]
13#[derive(Debug, PartialEq)]
14pub struct BSExtraData {
15 pub vtbl: *const BSExtraDataVtbl,
17 pub next: *mut BSExtraData,
26 marker: PhantomData<BSExtraData>,
28}
29
30const _: () = assert!(core::mem::size_of::<BSExtraData>() == 0x10);
31
32impl BSExtraData {
33 pub const RTTI: VariantID = RTTI_BSExtraData;
35
36 pub const VTABLE: [VariantID; 1] = VTABLE_BSExtraData;
38
39 pub const EXTRA_DATA_TYPE: ExtraDataType = ExtraDataType::None;
41
42 #[inline]
44 pub const fn new() -> Self {
45 Self { vtbl: &BS_EXTRA_DATA_VTBL, next: ptr::null_mut(), marker: PhantomData }
46 }
47
48 #[inline]
50 pub fn get_type(&self) -> ExtraDataType {
51 let vtable = match Self::VTABLE[0].address() {
52 Ok(addr) => addr.cast::<BSExtraDataVtbl>(),
53 Err(_err) => {
54 #[cfg(feature = "tracing")]
55 tracing::error!("Failed to get address of vtable: {_err}");
56 return (BS_EXTRA_DATA_VTBL.GetType)(self);
57 }
58 };
59 unsafe { (vtable.as_ref().GetType)(self) }
60 }
61
62 #[inline]
64 pub fn is_not_equal(&self, rhs: &Self) -> bool {
65 let vtable = match Self::VTABLE[0].address() {
66 Ok(addr) => addr.cast::<BSExtraDataVtbl>(),
67 Err(_err) => {
68 #[cfg(feature = "tracing")]
69 tracing::error!("Failed to get address of vtable: {_err}");
70 return false;
71 }
72 };
73 unsafe { (vtable.as_ref().IsNotEqual)(self, rhs) }
74 }
75
76 pub fn create<T: CxxVirtClass>() -> Option<NonNull<T>> {
80 let t = &T::vtable()[0];
81 Self::create_with(core::mem::size_of::<T>(), t.address().ok()?).map(|void| void.cast())
82 }
83
84 #[inline]
89 pub fn create_with(size: usize, vtbl: NonNull<c_void>) -> Option<NonNull<c_void>> {
90 use core::alloc::Layout;
91 use core::mem::align_of;
92 use std::alloc::alloc_zeroed;
93
94 unsafe {
95 let memory = {
96 let layout = Layout::from_size_align(size, align_of::<Self>()).ok()?;
97 NonNull::new(alloc_zeroed(layout))?
98 };
99
100 let vtable_ptr = memory.cast();
101 vtable_ptr.write(vtbl);
102
103 Some(memory.cast())
104 }
105 }
106}
107
108#[inline]
109pub fn downcast_as<T>(extra_data: *mut BSExtraData) -> Option<NonNull<T>> {
110 if extra_data.is_null() || !extra_data.is_aligned() {
111 return None;
112 }
113
114 if crate::rex::win32::is_valid_range(extra_data.cast(), core::mem::size_of::<T>()) {
115 return Some(unsafe { NonNull::new_unchecked(extra_data.cast::<T>()) });
116 };
117 None
118}
119
120pub trait DerivedBSExtraData {
124 fn get_extra_data(&self) -> &BSExtraData;
126 fn get_extra_data_type() -> ExtraDataType;
128}
129
130impl DerivedBSExtraData for BSExtraData {
131 #[inline]
132 fn get_extra_data(&self) -> &BSExtraData {
133 self
134 }
135
136 #[inline]
137 fn get_extra_data_type() -> ExtraDataType {
138 Self::EXTRA_DATA_TYPE
139 }
140}
141
142impl CxxVirtClass for BSExtraData {
143 #[inline]
144 fn rtti() -> &'static VariantID {
145 &Self::RTTI
146 }
147
148 #[inline]
149 fn vtable() -> &'static [VariantID] {
150 &Self::VTABLE
151 }
152}
153
154impl Default for BSExtraData {
155 #[inline]
156 fn default() -> Self {
157 Self::new()
158 }
159}
160
161static BS_EXTRA_DATA_VTBL: BSExtraDataVtbl = BSExtraDataVtbl::new();
163
164#[repr(C)]
166pub struct BSExtraDataVtbl {
167 pub CxxDrop: fn(this: &mut BSExtraData),
169
170 pub GetType: fn(this: &BSExtraData) -> ExtraDataType,
172
173 pub IsNotEqual: fn(this: &BSExtraData, rhs: &BSExtraData) -> bool,
175}
176
177impl BSExtraDataVtbl {
178 #[inline]
180 const fn new() -> Self {
181 const fn CxxDrop(_this: &mut BSExtraData) {}
182
183 const fn GetType(_this: &BSExtraData) -> ExtraDataType {
184 BSExtraData::EXTRA_DATA_TYPE
185 }
186
187 const fn IsNotEqual(_this: &BSExtraData, _rhs: &BSExtraData) -> bool {
188 false
189 }
190
191 Self { CxxDrop, GetType, IsNotEqual }
192 }
193}
194
195pub struct BSExtraDataIter<'a> {
197 pub(crate) current: *mut BSExtraData,
199
200 pub(crate) prev: *mut BSExtraData,
202
203 marker: PhantomData<&'a BSExtraData>,
205}
206
207impl BSExtraDataIter<'_> {
208 #[inline]
210 pub const fn new(start: *mut BSExtraData) -> Self {
211 Self { current: start, prev: std::ptr::null_mut(), marker: PhantomData }
212 }
213
214 pub fn remove_current(&mut self) -> Option<*mut BSExtraData> {
219 if self.current.is_null() {
220 return None;
221 }
222
223 let removed = self.current;
224 unsafe {
225 let next = (*removed).next;
226
227 if !self.prev.is_null() {
228 (*self.prev).next = next;
229 }
230
231 self.current = next;
232 }
233
234 Some(removed)
235 }
236}
237
238impl Iterator for BSExtraDataIter<'_> {
239 type Item = *mut BSExtraData;
240
241 fn next(&mut self) -> Option<Self::Item> {
242 if self.current.is_null() {
243 return None;
244 }
245
246 let current = self.current;
247 unsafe {
248 self.prev = current;
249 self.current = (*current).next;
250 }
251 Some(current)
252 }
253}
254
255pub struct BSExtraDataIterMut<'a> {
257 cur: *mut BSExtraData,
258 prev: *mut BSExtraData,
259 marker: PhantomData<&'a BSExtraData>,
260}
261
262impl BSExtraDataIterMut<'_> {
263 #[inline]
265 pub const fn new(start: *mut BSExtraData) -> Self {
266 Self { cur: start, prev: std::ptr::null_mut(), marker: PhantomData }
267 }
268
269 pub fn remove_current(&mut self) {
271 if self.cur.is_null() {
272 return;
273 }
274
275 let next = (unsafe { &*self.cur }).next;
276
277 if !self.prev.is_null() {
278 (unsafe { &mut *self.prev }).next = next;
279 }
280
281 let to_delete = self.cur;
282 self.cur = next;
283
284 drop(unsafe { Box::from_raw(to_delete) });
286 }
287}
288
289impl Iterator for BSExtraDataIterMut<'_> {
290 type Item = *mut BSExtraData;
291
292 fn next(&mut self) -> Option<Self::Item> {
293 if self.cur.is_null() {
294 return None;
295 }
296
297 let current = self.cur;
298 unsafe {
299 self.prev = current;
300 self.cur = (*current).next;
301 }
302 Some(current)
303 }
304}
305
306