Crates.io | vtable-rs |
lib.rs | vtable-rs |
version | 0.1.1 |
source | src |
created_at | 2024-10-07 03:06:15.557854 |
updated_at | 2024-10-07 03:45:30.986931 |
description | Set of traits and macros to help dealing with C++ virtual method FFI |
homepage | |
repository | https://github.com/tremwil/vtable-rs |
max_upload_size | |
id | 1399619 |
size | 7,775 |
Attribute proc macro that can be used to turn a dyn-compatible trait definition into a C++ compatible vtable definition.
Mainly intended for making mods/memory hacking C++ applications.
For a usage example, say we have a C++ abstract class of the form
struct Obj {
uint32_t field;
virtual ~Obj() = default;
virtual uint32_t method(uint32_t arg) const noexcept = 0;
};
This macro then allows us to represent Obj
's virtual function table in Rust
and provide our own implementations:
use vtable_rs::{vtable, VPtr};
#[vtable]
pub trait ObjVmt {
fn destructor(&mut self) {
// We can provide a default implementation too!
}
fn method(&self, arg: u32) -> u32;
}
// VPtr implements Default for types that implement the trait, and provides
// a compile-time generated vtable!
#[derive(Default)]
#[repr(C)]
struct RustObj {
vftable: VPtr<dyn ObjVmt, Self>,
field: u32
}
impl ObjVmt for RustObj {
extern "C" fn method(&self, arg: u32) -> u32 {
self.field + arg
}
}
RustObj
could then be passed to a C++ function that takes in a pointer to Obj
.
The macro supports single inhertiance through a single trait bound, e.g.
#[vtable]
pub trait DerivedObjVmt: ObjVmt {
unsafe fn additional_method(&mut self, s: *const c_char);
}
The vtable layout is fully typed and can be accessed as <dyn TraitName as VmtLayout>::Layout<T>
.
A VPtr
can be Deref
'd into it to obtain the bare function pointers and thus call through
the vtable directly:
let obj = RustObj::default();
let method_impl = obj.vftable.method; // extern "C" fn(&RustObj, u32) -> u32
let call_result = method_impl(obj, 42);