12个版本 (2个稳定版)

1.1.0 2024年7月20日
1.0.0 2024年6月21日
0.3.0 2023年12月6日
0.2.1 2023年4月5日
0.1.7 2022年10月3日

#145过程宏

Download history 32/week @ 2024-04-25 151/week @ 2024-06-20 2/week @ 2024-06-27 20/week @ 2024-07-04 126/week @ 2024-07-18 18/week @ 2024-07-25 10/week @ 2024-08-01

每月154次下载

MIT 许可证

65KB
1.5K SLoC

VTable Gen

此crate提供宏,通过定义结构和vtable布局来生成C++-ABI VTables。它还支持VTable继承和基本类继承。

示例

查看tests.rs,相当直观。

用法

基本结构体

  • 定义一个包含虚函数的结构体
  • 定义一个与所属结构体名称完全匹配的VTable结构体,后面紧跟VTable。示例
struct Foo {}
struct FooVTable {}
  • 使用#[gen_vtable]标记VTable和结构体。VTable结构体中包含的任何函数指针都需要在自动生成的<name>Virtuals特质中实现。完整示例
#[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属性。示例
#[gen_vtable]
struct Foo {}
#[gen_vtable]
struct FooVTable {}

#[gen_vtable(base = "Foo")]
struct Bar {}
#[gen_vtable(base = "Foo")]
struct BarVTable {}

使用VTable构造结构体

使用VTable构造结构体非常简单。如果结构体是可默认的,只需派生DefaultVTable而不是Default。这将impl Default。如果结构体不可默认,则定义一些函数fn new(/* args */) -> Self。使用new_with_vtable标记该函数,如果需要,可以像在Derived Structs中那样提供基结构体。为了让编译器知道类型,您必须明确地将返回类型中的Self替换为实际类型,或者指定self_type。以下是一个详尽的示例

// ...
impl Bar {
    #[new_with_vtable(self_type = "Bar")]
    fn new(baz: u32) -> Self {
        Self { baz }
    }
}

这同样等效于

// ...
impl Bar {
    #[new_with_vtable]
    fn new(baz: u32) -> Bar {
        Self { baz }
    }
}

如果有基结构体需要调用其new函数,您还必须显式初始化一个base_with_vtbl成员,该成员使用子类型的new构造函数。例如

// ...
impl Bar {
    #[new_with_vtable(base = "Foo", self_type = "Bar")]
    fn new(baz: u32) -> Self {
        Self {
            base_with_vtable: Foo::new(123),
            baz
        }
    }
}

重写函数

重写函数很简单。因为所有函数都在Traits中定义,所以可以指定编译器不要为具有no_base_trait_impl参数的VTable(或两者都为了对称性:)))的基结构体Virtuals生成实现。示例

// ...
#[gen_vtable(base = "Foo", no_base_trait_impl)]
struct BarVTable {}
// ...
impl FooVirtuals for Bar {
    extern "C" fn some_fn(this: &Foo) {
        // ...
    }
}

唯一的限制是您必须实现所有基特质。

自动实现

对于自动实现,例如对于某些抽象结构体,只需将unimpl作为参数传递给gen_vtable,所有方法都将使用unimplemented!()实现。示例

// ...
#[gen_vtable(unimpl)]
struct Foo {}
#[gen_vtable(unimpl)]
struct FooVTable {}

// `FooVirtuals` is implemented for `Foo`

已知限制

  • vtable_gen目前不支持泛型结构体。然而,这是一个微不足道的添加,并且可能在未来添加。

依赖关系

~1.6–2.1MB
~41K SLoC