Skip to content

Commit 8c4dc18

Browse files
committed
Add opaque structs to TRPL:FFI
Fixes #27303
1 parent d034561 commit 8c4dc18

File tree

1 file changed

+53
-0
lines changed

1 file changed

+53
-0
lines changed

src/doc/trpl/ffi.md

+53
Original file line numberDiff line numberDiff line change
@@ -555,3 +555,56 @@ pub extern fn oh_no() -> i32 {
555555
# fn main() {}
556556
```
557557

558+
# Representing opaque structs
559+
560+
Sometimes, a C library wants to provide a pointer to something, but not let you
561+
know the internal details of the thing it wants. The simplest way is to use a
562+
`void *` argument:
563+
564+
```c
565+
void foo(void *arg);
566+
void bar(void *arg);
567+
```
568+
569+
We can represent this in Rust with the `c_void` type:
570+
571+
```rust
572+
# #![feature(libc)]
573+
extern crate libc;
574+
575+
extern "C" {
576+
pub fn foo(arg: *mut libc::c_void);
577+
pub fn bar(arg: *mut libc::c_void);
578+
}
579+
# fn main() {}
580+
```
581+
582+
This is a perfectly valid way of handling the situation. However, we can do a bit
583+
better. To solve this, some C libraries will instead create a `struct`, where
584+
the details and memory layout of the struct are private. This gives some amount
585+
of type safety. These structures are called ‘opaque’. Here’s an example, in C:
586+
587+
```c
588+
struct Foo; /* Foo is a structure, but its contents are not part of the public interface */
589+
struct Bar;
590+
void foo(struct Foo *arg);
591+
void bar(struct Bar *arg);
592+
```
593+
594+
To do this in Rust, let’s create our own opaque types with `enum`:
595+
596+
```rust
597+
pub enum Foo {}
598+
pub enum Bar {}
599+
600+
extern "C" {
601+
pub fn foo(arg: *mut Foo);
602+
pub fn bar(arg: *mut Bar);
603+
}
604+
# fn main() {}
605+
```
606+
607+
By using an `enum` with no variants, we create an opaque type that we can’t
608+
instantiate, as it has no variants. But because our `Foo` and `Bar` types are
609+
different, we’ll get type safety between the two of them, so we cannot
610+
accidentally pass a pointer to `Foo` to `bar()`.

0 commit comments

Comments
 (0)