Пока еще нет способа автоматически создавать определения типов Rust из структур Си.В этих ситуациях есть несколько способов действовать.Не зная MySQL API, я не могу точно сказать, что вам следует делать, но вот несколько вариантов.
1) Относитесь к ним как к непрозрачным указателям.
Это лучшая ситуация длябыть в, и зависит от C API, всегда принимающего структуру в качестве указателя, имеющего свои собственные функции конструктора и деструктора и обеспечивающего функции доступа для всего, что вам нужно для доступа внутри структуры.В этих случаях вы просто определяете type MYSQL = ctypes::void
и используете его только как небезопасный указатель *MYSQL
.Иногда самый простой путь - написать свои собственные оболочки C, чтобы заполнить пробелы и сделать этот сценарий возможным.
Все остальные сценарии включают переопределение структуры данных Rust с той же структурой, что и структура C.Rust пытается расположить свои структуры данных таким образом, чтобы он был совместим с C (хотя это еще не всегда удавалось), поэтому часто можно создать запись или перечисление Rust с размером, выравниванием и расположением структуры C, которую вы используете.заботиться о.Вам нужно убедиться, что вы используете типы в 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
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.