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