What Rust idiom defines a field that points to an opaque C pointer?
Given the structure:
#[repr(C)]
pub struct User {
pub name: *const c_char,
pub age: u8,
pub ctx: ??,
}
the field ctx
will be processed only by the C code; it is a pointer to a C struct UserAttr
.
According to the Rust RFI documentation , the selection will be defined as an opaque type pub enum UserAttr {}
. However, I found that Rust cannot copy its value for example. why the address of the object is changed using methods .
What's the correct way in Rust to define such an opaque pointer so that its value (as a pointer) is copied through methods?
source to share
The documentation doesn't lie to you:
To do this in Rust, create your own opaque types with
enum
:
pub enum Foo {} pub enum Bar {} extern "C" { pub fn foo(arg: *mut Foo); pub fn bar(arg: *mut Bar); }
By using
enum
no variants, we create an opaque type, which we cannot be instantiated as it has no variants. But since oursFoo
andBar
types are different, it's good to get type safety between them, so we can't accidentally pass a pointerFoo
tobar()
.
A transparent pointer is usually enum Foo {}
because there is no normal way to create this type. You can create pointers to it.
mod ffi {
use std::ptr;
pub enum MyTypeFromC {}
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();
}
A bit to break:
// opaque -----V~~~~~~~~~V
*mut MyTypeFromC
// ^~~^ ------------ pointer
Thus, it is an opaque pointer. Moving the structure MyRustType
will not change the pointer value.
RFC 1861 introduced the outer type concept. Although implemented, it has not yet stabilized. Once that happens, this becomes the preferred implementation:
#![feature(extern_types)]
extern "C" {
type Foo;
}
type FooPtr = *mut Foo;
source to share