目前还没有自动从C结构体创建Rust类型定义的方法。在这种情况下,有几种处理方式。由于我不了解MySQL API,无法确定应该采取哪种方式,但以下是一些选择。
1) 将其完全视为不透明指针。
这是最好的情况,并且取决于C API始终将结构作为指针传递,具有自己的构造函数和析构函数,并提供访问结构内部任何需要访问的内容的访问器函数。在这些情况下,您只需定义
type MYSQL = ctypes :: void
并始终将其用作不安全指针
* MYSQL
。有时候,最简单的方法是编写自己的C包装器来填补空白,使此场景成为可能。
其余情况都涉及重新定义与C结构相同结构的Rust数据结构。 Rust尝试以与C兼容的方式布置其数据结构(尽管尚未总是成功),因此通常可以创建具有您关心的C结构的大小,对齐和布局的Rust记录或枚举。您将希望确保使用
core :: ctypes
中的类型,因为它们被定义为与各种常见的C类型匹配。
请注意,
ctypes
模块即将被淘汰,取而代之的是更全面的libc兼容模块。
2) 定义一个部分正确的Rust记录。
如果API提供了构造函数和析构函数,但你仍然需要访问结构体的某些字段,则可以定义足够的结构体以访问你关心的字段,忽略正确的大小和对齐方式。例如:
type MSQL = { filler1: ctypes::int, ..., connector_fd: *ctypes::char }
。你可以在你关心的最后一个字段停止定义结构体,因为你有一个C函数来以正确的大小和对齐方式在堆上分配它。在Rust代码中,你总是使用不安全指针引用它:
let mysql: *MYSQL = mysqlrust::create_mysql();
3) 定义一个正确大小和对齐的Rust记录,不关心其内容。
如果您没有构造函数/析构函数,或需要将结构体存储在堆栈上,但是您有访问器函数以操作结构体的内容,则需要定义一个具有正确大小和对齐方式的Rust记录。为此,只需添加类型为uint(始终为指针大小)或uint元组的字段,直到C的sizeof和core::sys::size_of同意大小。如果大小不是指针大小的倍数,请使用u8进行填充。正确获取对齐方式是一个更加神秘的过程,但是使用uint字段,您通常会得到可用的对齐方式(也许-我真的不知道这个说法的准确性)。
我建议添加测试来检查Rust和C是否同意大小,以防止未来的破坏。
3)重新定义整个C结构体。
对于大型结构体来说,这是一种非常严重的情况,理论上可能会发生,但我认为没有人像MYSQL那样做过这样大的结构体。如果可以的话,我会避免它。最终将会有基于clang的工具自动执行此操作。
以下是与C结构体互操作的一些示例:
https://github.com/jdm/rust-socket/blob/master/socket.rs - 这个重新定义了一些套接字结构,为它不关心的字段添加了占位符。请注意,它使用u8
进行填充,但我认为uint
更有可能产生正确的对齐方式。
https://github.com/erickt/rust-zmq/blob/master/zmq.rs
https://github.com/pcwalton/rust-spidermonkey - 这个示例展示了与一个相对复杂的API进行交互。