vtable-rs

Crates.iovtable-rs
lib.rsvtable-rs
version
sourcesrc
created_at2024-10-07 03:06:15.557854
updated_at2024-12-01 03:53:38.849855
descriptionSet of traits and macros to help dealing with C++ virtual method FFI
homepage
repositoryhttps://github.com/tremwil/vtable-rs
max_upload_size
id1399619
Cargo.toml error:TOML parse error at line 18, column 1 | 18 | autolib = false | ^^^^^^^ unknown field `autolib`, expected one of `name`, `version`, `edition`, `authors`, `description`, `readme`, `license`, `repository`, `homepage`, `documentation`, `build`, `resolver`, `links`, `default-run`, `default_dash_run`, `rust-version`, `rust_dash_version`, `rust_version`, `license-file`, `license_dash_file`, `license_file`, `licenseFile`, `license_capital_file`, `forced-target`, `forced_dash_target`, `autobins`, `autotests`, `autoexamples`, `autobenches`, `publish`, `metadata`, `keywords`, `categories`, `exclude`, `include`
size0
William Tremblay (tremwil)

documentation

README

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);
Commit count: 20

cargo fmt