Crates.io | vtable_gen |
lib.rs | vtable_gen |
version | 1.1.0 |
source | src |
created_at | 2022-10-02 06:00:48.26503 |
updated_at | 2024-07-20 09:18:08.314316 |
description | A C++-ABI VTable Generator for Rust |
homepage | |
repository | https://github.com/MrElectrify/vtable_gen |
max_upload_size | |
id | 678155 |
size | 100,123 |
This crate provides macros to generate C++-ABI VTables by defining the structure and vtable layout. It also supports VTable inheritance and basic class inheritance.
Check out tests.rs
, which is pretty self-explanatory.
VTable
exactly. Example:struct Foo {}
struct FooVTable {}
#[gen_vtable]
. Any function pointers you include in
the VTable struct will require implementation in an automatically-generated <name>Virtuals
trait.
Complete Example:#[gen_vtable]
struct Foo {}
#[gen_vtable]
struct FooVTable {
foo: extern "C" fn(this: &Foo) -> u32;
}
impl FooVirtuals for Foo {
extern "C" fn foo(this: &Foo) -> u32 { todo!() }
}
base
. Example:#[gen_vtable]
struct Foo {}
#[gen_vtable]
struct FooVTable {}
#[gen_vtable(base = "Foo")]
struct Bar {}
#[gen_vtable(base = "Foo")]
struct BarVTable {}
Constructing structs with VTables is easy. If the struct is default-able, simply derive
DefaultVTable
instead of Default
. This will impl Default
. If the struct isn't default-able,
define some function fn new(/* args */) -> Self
. Mark the function with new_with_vtable
,
supplying base structs if necessary as in Derived Structs
. For the compiler to know the type,
you must either explicitly replace Self
as the return type with the type itself, or specify
self_type
. Here's a verbose example:
// ...
impl Bar {
#[new_with_vtable(self_type = "Bar")]
fn new(baz: u32) -> Self {
Self { baz }
}
}
which is also equivalent to
// ...
impl Bar {
#[new_with_vtable]
fn new(baz: u32) -> Bar {
Self { baz }
}
}
If there is a base struct that requires its new
function to be called, you will have to also
explicitly initialize a base_with_vtbl
member with the new
constructor of the child type.
For example:
// ...
impl Bar {
#[new_with_vtable(base = "Foo", self_type = "Bar")]
fn new(baz: u32) -> Self {
Self {
base_with_vtable: Foo::new(123),
baz
}
}
}
Overriding functions is easy. Because all functions are defined in Traits, one can specify for the
compiler to not generate implementations for base struct Virtuals
with the argument no_base_trait_impl
on the VTable (or both for symmetry :)).
Example:
// ...
#[gen_vtable(base = "Foo", no_base_trait_impl)]
struct BarVTable {}
// ...
impl FooVirtuals for Bar {
extern "C" fn some_fn(this: &Foo) {
// ...
}
}
The only caveat is you will have to implement all base traits.
For an automatic implementation, in the case of some abstract struct for example, simply supply unimpl
as an argument to gen_vtable
, and all methods will be implemented with unimplemented!()
. Example:
// ...
#[gen_vtable(unimpl)]
struct Foo {}
#[gen_vtable(unimpl)]
struct FooVTable {}
// `FooVirtuals` is implemented for `Foo`
vtable_gen
currently does not support generic structs. This is a trivial addition, however, and
will likely be added in the future