paavohtl Claude Opus 4.6 (1M context) commited on
Commit
af1e67a
·
1 Parent(s): 94f0eda

feat: add Vtable marker trait for CTask<V> type safety

Browse files

Add unsafe trait Vtable as a bound on CTask<V> and CGameTask<V>,
preventing arbitrary types from being used as vtable parameters.

- *const c_void implements Vtable (the default/untyped case)
- #[vtable] proc macro auto-generates `impl Vtable for *const MyVTable`
- CTask<V: Vtable> and CGameTask<V: Vtable> enforce the bound

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

crates/openwa-core/src/task/base.rs CHANGED
@@ -105,7 +105,7 @@ crate::define_addresses! {
105
  /// 0x1C: 0x563210 ProcessFrame
106
  #[derive(FieldRegistry)]
107
  #[repr(C)]
108
- pub struct CTask<V: 'static = *const core::ffi::c_void> {
109
  /// 0x00: Pointer to virtual method table
110
  pub vtable: V,
111
  /// 0x04: Parent task in the hierarchy
@@ -141,6 +141,18 @@ pub struct CTask<V: 'static = *const core::ffi::c_void> {
141
 
142
  const _: () = assert!(core::mem::size_of::<CTask>() == 0x30);
143
 
 
 
 
 
 
 
 
 
 
 
 
 
144
  /// Trait for all task types in the CTask hierarchy.
145
  ///
146
  /// Provides safe access to the underlying CTask fields regardless of
@@ -177,7 +189,7 @@ pub unsafe trait Task {
177
  }
178
 
179
  // Blanket impl for any CTask<V>
180
- unsafe impl<V: 'static> Task for CTask<V> {}
181
 
182
  // ---------------------------------------------------------------------------
183
  // Shared-data entity registry
 
105
  /// 0x1C: 0x563210 ProcessFrame
106
  #[derive(FieldRegistry)]
107
  #[repr(C)]
108
+ pub struct CTask<V: Vtable = *const core::ffi::c_void> {
109
  /// 0x00: Pointer to virtual method table
110
  pub vtable: V,
111
  /// 0x04: Parent task in the hierarchy
 
141
 
142
  const _: () = assert!(core::mem::size_of::<CTask>() == 0x30);
143
 
144
+ /// Marker trait for types that can be used as vtable pointers in `CTask<V>`.
145
+ ///
146
+ /// Implemented automatically by the `#[vtable]` proc macro for `*const MyVTable`.
147
+ /// Also implemented for `*const c_void` (the default/untyped case).
148
+ ///
149
+ /// # Safety
150
+ /// Implementors must be pointer-sized types pointing to valid vtable data.
151
+ pub unsafe trait Vtable: 'static {}
152
+
153
+ // Default vtable type (untyped)
154
+ unsafe impl Vtable for *const core::ffi::c_void {}
155
+
156
  /// Trait for all task types in the CTask hierarchy.
157
  ///
158
  /// Provides safe access to the underlying CTask fields regardless of
 
189
  }
190
 
191
  // Blanket impl for any CTask<V>
192
+ unsafe impl<V: Vtable> Task for CTask<V> {}
193
 
194
  // ---------------------------------------------------------------------------
195
  // Shared-data entity registry
crates/openwa-core/src/task/game_task.rs CHANGED
@@ -31,7 +31,7 @@ pub const CGAMETASK_SOUND_EMITTER_VT: u32 = SOUND_EMITTER_VTABLE;
31
  /// Additional vtable (12 methods at offsets 0x1C-0x48 in vtable)
32
  #[derive(FieldRegistry)]
33
  #[repr(C)]
34
- pub struct CGameTask<V: 'static = *const core::ffi::c_void> {
35
  /// 0x00-0x2F: Base CTask fields
36
  pub base: CTask<V>,
37
  /// 0x30-0x83: Subclass-specific data (84 bytes). Each CGameTask derivative
 
31
  /// Additional vtable (12 methods at offsets 0x1C-0x48 in vtable)
32
  #[derive(FieldRegistry)]
33
  #[repr(C)]
34
+ pub struct CGameTask<V: super::base::Vtable = *const core::ffi::c_void> {
35
  /// 0x00-0x2F: Base CTask fields
36
  pub base: CTask<V>,
37
  /// 0x30-0x83: Subclass-specific data (84 bytes). Each CGameTask derivative
crates/openwa-core/src/task/mod.rs CHANGED
@@ -14,7 +14,7 @@ pub mod turn_game;
14
  pub mod worm;
15
 
16
  pub use arrow::{CTaskArrow, CTaskArrowVTable};
17
- pub use base::{CTask, CTaskBfsIter, SharedDataIter, SharedDataNode, SharedDataTable, Task};
18
  pub use cloud::{CTaskCloud, CTaskCloudVTable};
19
  pub use filter::{CTaskFilter, CTaskFilterVTable};
20
  pub use fire::{CTaskFire, CTaskFireVTable};
@@ -29,7 +29,7 @@ pub use worm::{CTaskWorm, CTaskWormVTable};
29
 
30
  // Task trait impls — safe access to CTask base regardless of inheritance depth.
31
  // CTask<V> impl is in base.rs (blanket impl).
32
- unsafe impl<V: 'static> Task for CGameTask<V> {}
33
  unsafe impl Task for CTaskTeam {}
34
  unsafe impl Task for CTaskTurnGame {}
35
  unsafe impl Task for CTaskFilter {}
 
14
  pub mod worm;
15
 
16
  pub use arrow::{CTaskArrow, CTaskArrowVTable};
17
+ pub use base::{CTask, CTaskBfsIter, SharedDataIter, SharedDataNode, SharedDataTable, Task, Vtable};
18
  pub use cloud::{CTaskCloud, CTaskCloudVTable};
19
  pub use filter::{CTaskFilter, CTaskFilterVTable};
20
  pub use fire::{CTaskFire, CTaskFireVTable};
 
29
 
30
  // Task trait impls — safe access to CTask base regardless of inheritance depth.
31
  // CTask<V> impl is in base.rs (blanket impl).
32
+ unsafe impl<V: Vtable> Task for CGameTask<V> {}
33
  unsafe impl Task for CTaskTeam {}
34
  unsafe impl Task for CTaskTurnGame {}
35
  unsafe impl Task for CTaskFilter {}
crates/openwa-derive/src/lib.rs CHANGED
@@ -311,6 +311,9 @@ fn vtable_impl(
311
 
312
  #va_items
313
 
 
 
 
314
  /// Bind this vtable's known methods as wrapper methods on a class struct.
315
  ///
316
  /// Usage: `bind_VtableName!(ClassName, vtable_field_name);`
 
311
 
312
  #va_items
313
 
314
+ // Mark *const ThisVtable as a valid vtable pointer type for CTask<V>.
315
+ unsafe impl openwa_core::task::Vtable for *const #struct_name {}
316
+
317
  /// Bind this vtable's known methods as wrapper methods on a class struct.
318
  ///
319
  /// Usage: `bind_VtableName!(ClassName, vtable_field_name);`