¿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 tiposFoo
yBar
son diferentes, obtendremos seguridad de tipo entre los dos, por lo que no podemos pasar accidentalmente un puntero aFoo
abar()
.
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?