目前还没有任何方法可以从 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
,直到 Csizeof
和Ccore::sys::size_of
都同意大小。u8
如果大小不是指针大小的倍数,则用s 填充。正确对齐是一个更神秘的过程,但是通过使用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 的互操作。