Aún no hay forma de crear automáticamente definiciones de tipo Rust a partir de estructuras C. En estas situaciones, hay algunas maneras de proceder. Al no conocer la API de MySQL, no puedo decir exactamente lo que debe hacer, pero aquí hay algunas opciones.
1) Trátelos por completo como punteros opacos.
Esta es la mejor situación para estar, y depende de que la API C siempre tome la estructura como puntero, tenga sus propias funciones de constructor y destructor y proporcione funciones de acceso para lo que necesite acceder dentro de la estructura. En estos casos, solo define type MYSQL = ctypes::void
y solo lo usa como un puntero inseguro *MYSQL
. Algunas veces, la ruta más fácil es escribir sus propios envoltorios de C para llenar los vacíos y hacer posible este escenario.
El resto de los escenarios implican la redefinición de una estructura de datos Rust con la misma estructura que la estructura C. Rust intenta diseñar sus estructuras de datos de una manera que sea compatible con C (aunque no siempre lo logra), por lo que a menudo es posible crear un registro o enumeración de Rust con el tamaño, la alineación y el diseño de la estructura C preocuparse. Deberá asegurarse de utilizar los tipos en core::ctypes
, ya que están definidos para coincidir con varios tipos de C comunes.
Tenga en cuenta que el módulo ctypes
desaparecerá pronto a favor de un módulo de compatibilidad de libc más completo.
2) Defina un registro de Rust parcialmente correcto.
Si la API proporciona constructores y destructores, pero aún necesita acceso a algunos campos de la estructura, puede definir lo suficiente de la estructura para llegar a los campos que le interesan, sin tener en cuenta el tamaño y la alineación correctos . p.ej. type MSQL = { filler1: ctypes::int, ..., connector_fd: *ctypes::char }
. Puede dejar de definir la estructura en el último campo que le interesa ya que tiene una función C para asignarla en el montón con el tamaño y la alineación correctos. En el código Rust siempre se refiere a él con un puntero inseguro: let mysql: *MYSQL = mysqlrust::create_mysql();
3) Defina un registro de óxido que tenga el tamaño y la alineación correctos, sin preocuparse por el contenido.
Si no tiene funciones de constructor/destructor, o necesita almacenar la estructura en la pila, pero tiene funciones de acceso para manipular el contenido de la estructura, entonces necesita definir un registro de Rust con la correcta tamaño y alineación Para hacer esto, simplemente agregue los campos del tipo uint
(que siempre es del tamaño de un puntero) o tuplas de uint
, hasta que ambos C sizeof
y core::sys::size_of
acuerden el tamaño. Rellene con u8
s si el tamaño no es un múltiplo del tamaño del puntero. Obtener la alineación correcta es un proceso más místico, pero al usar los campos uint
generalmente terminará con una alineación utilizable (tal vez, realmente no tengo idea de qué tan precisa es esa afirmación).
Recomendaría agregar pruebas a la comprobación de cordura que Rust y C acuerden sobre el tamaño para evitar futuras roturas.
3) En realidad redefinir toda la estructura C.
Esta es una situación bastante grave para grandes estructuras, y es posible en teoría, pero no creo que nadie lo haya hecho para una estructura tan grande como MYSQL
. Lo evitaría si puedes. Eventualmente habrá una herramienta basada en clang para hacer esto automáticamente.
Éstos son algunos ejemplos de interoperabilidad con estructuras C:
https://github.com/jdm/rust-socket/blob/master/socket.rs - Este redefine diversas estructuras de socket, la adición de marcadores de posición para los campos que no le interesan en. Tenga en cuenta que utiliza u8
para el relleno, pero creo que uint
es más probable que produzca una alineación correcta.
https://github.com/erickt/rust-zmq/blob/master/zmq.rs
https://github.com/pcwalton/rust-spidermonkey - Éste demuestra interoperabilidad con un API algo complejo.
Veamos el código que ha escrito y los mensajes de error exactos – Mark
http://doc.rust-lang.org/doc/tutorial.html#passing-structures –