rust

¿Cuál es el idioma de Rust para definir un campo que apunta a un puntero opaco en C?



(1)

El futuro

RFC 1861 introdujo el concepto de un tipo externo . Mientras está implementado, aún no está estabilizado. Una vez que sea así, se convertirá en la implementación preferida:

#![feature(extern_types)] extern "C" { type Foo; } type FooPtr = *mut Foo;

Hoy

La documentación dice:

Para hacer esto en Rust, creemos nuestros propios tipos opacos:

#[repr(C)] pub struct Foo { private: [u8; 0] } #[repr(C)] pub struct Bar { private: [u8; 0] } extern "C" { pub fn foo(arg: *mut Foo); pub fn bar(arg: *mut Bar); }

Al incluir un campo privado y ningún constructor, creamos un tipo opaco que no podemos instanciar fuera de este módulo. Una matriz vacía es de tamaño cero y compatible con #[repr(C)] . Pero debido a que nuestros tipos Foo y Bar son diferentes, obtendremos seguridad de tipo entre los dos, por lo que no podemos pasar accidentalmente un puntero a Foo a bar() .

Se crea un puntero opaco de manera que no haya una forma normal de crear dicho tipo; solo puedes crearle punteros.

mod ffi { use std::ptr; pub struct MyTypeFromC { _private: [u8; 0] } pub fn constructor() -> *mut MyTypeFromC { ptr::null_mut() } pub fn something(_thing: *mut MyTypeFromC) { println!("Doing a thing"); } } use ffi::*; struct MyRustType { score: u8, the_c_thing: *mut MyTypeFromC, } impl MyRustType { fn new() -> MyRustType { MyRustType { score: 42, the_c_thing: constructor(), } } fn something(&mut self) { println!("My score is {}", self.score); ffi::something(self.the_c_thing); self.score += 1; } } fn main() { let mut my_thing = MyRustType::new(); my_thing.something(); }

Desglosándolo un poco:

// opaque -----V~~~~~~~~~V *mut MyTypeFromC // ^~~^ ------------ pointer

Por lo tanto, es un puntero opaco. Mover la estructura MyRustType no cambiará el valor del puntero.

El pasado

Las iteraciones anteriores de esta respuesta y la documentación sugerían usar una enumeración vacía ( enum MyTypeFromC {} ). Una enumeración sin variantes es semánticamente equivalente al tipo nunca ( ! ), Que es un tipo que no puede existir. Existía la preocupación de que el uso de tal construcción podría conducir a un comportamiento indefinido, por lo que pasar a una matriz vacía se consideró más seguro.

Dada una estructura:

#[repr(C)] pub struct User { pub name: *const c_char, pub age: u8, pub ctx: ??, }

el campo ctx solo sería manipulado por el código C; es un puntero a un C struct UserAttr .

De acuerdo con la documentación de Rust FFI , la elección se definiría como un tipo opaco pub enum UserAttr {} . Sin embargo, descubrí que Rust no puede copiar su valor, por ejemplo, ¿ por qué la dirección de un objeto cambia a través de los métodos ?

¿Cuál es la forma correcta en Rust de definir un puntero tan opaco, para que su valor (como puntero) se copie entre los métodos?