Skip to content

Commit

Permalink
Update doc for unions
Browse files Browse the repository at this point in the history
Addresses rust-lang#832
  • Loading branch information
tmfink committed Aug 19, 2017
1 parent 5f627fd commit 074f1f1
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 32 deletions.
66 changes: 36 additions & 30 deletions book/src/using-unions.md
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
# Using the Union Types Generated by Bindgen

**NOTE:** As of Rust version 1.17, Rust does not have a stable `union` type. Issue [#32836](https://github.com/rust-lang/rust/issues/32836) tracks the stabilization of a `union` type in Rust.
**NOTE**: Rust 1.19 stabilized the `union` type (see Rust issue [#32836](https://github.com/rust-lang/rust/issues/32836)).

By using the flag `--unstable-rust`, bindgen will generate the preliminary unstable `union` type.
You can pass the `--rust-target` option to tell `bindgen` to target a specific version of Rust.
By default, `bindgen` will target the latest stable Rust.
The `--rust-target` option accepts a specific stable version (such as "1.0" or "1.19") or "nightly".

In general, most interactions with unions (either reading or writing) are unsafe.
**NOTE**: The `--unstable-rust` option is deprecated; use `--rust-target nightly` instead.

In general, most interactions with unions (either reading or writing) are unsafe, meaning you must surround union accesses in an `unsafe {}` block.

For this discussion, we will use the following C type definitions:

Expand All @@ -31,46 +35,47 @@ typedef union {

### Library

* [`bindgen::Builder::unstable_rust()`](https://docs.rs/bindgen/0.25.3/bindgen/struct.Builder.html#method.unstable_rust)
* [`bindgen::Builder::derive_default()`](https://docs.rs/bindgen/0.25.3/bindgen/struct.Builder.html#method.derive_default)
* [`bindgen::Builder::rust_target()`](https://docs.rs/bindgen/0.29.0/bindgen/struct.Builder.html#method.rust_target) <!-- Update when live -->
* [`bindgen::Builder::derive_default()`](https://docs.rs/bindgen/0.29.0/bindgen/struct.Builder.html#method.derive_default)

### Command Line

* `--unstable-rust`
* `--rust-target`
* `--with-derive-default`

## Using the unstable `union` version
## Which union type will Bindgen generate?

With `struct`s generated by bindgen from C, it is possible to initialize fields in a "normal" rust way:
Bindgen can emit one of two Rust types that correspond to C unions:

```rust,ignore
mod bindings;
* Rust's `union` builtin (only available in Rust >= 1.19, including nightly)
* Bindgen's `BindgenUnion` (available for all Rust targets)

fn main() {
let x = bindings::alpha_t {
a: 1,
b: -1,
};
}
```
Bindgen uses the following logic to determine which Rust union type to emit:

* If the Rust target is >= 1.19 (including nightly) AND each field of the union can derive `Copy`, then generate a `union` builtin.
* Otherwise, generate a `BindgenUnion`.

## Using the `union` builtin

When using the `union` builtin type, there are two choices for initialization:

When using the unstable `union` type, there are two choices for initialization: Zeroed, and with a specific variant.
1. Zero
2. With a specific variant

```rust,ignore
#![feature(untagged_unions)]
mod bindings_unstable;
mod bindings_builtin_union;
fn unstable() {
fn union_builtin() {
// Initalize the union to zero
let x = bindings_unstable::greek_t::default();
let x = bindings_builtin_union::greek_t::default();
// If `--with-derive-default` option is not used, the following may be used
// to initalize the union to zero:
let x = unsafe{ std::mem::zeroed::<bindings_unstable::greek_t>() };
let x = unsafe { std::mem::zeroed::<bindings_builtin_union::greek_t>() };
// Or, it is possible to initialize exactly one variant of the enum:
let x = bindings_unstable::greek_t {
alfa: bindings_unstable::alpha_t {
let x = bindings_builtin_union::greek_t {
alfa: bindings_builtin_union::alpha_t {
a: 1,
b: -1,
},
Expand All @@ -83,16 +88,17 @@ fn unstable() {
}
```

## Using the stable BindgenUnion types
## Using the `BindgenUnion` type

For versions of Rust that do not support the new `union` type, bindgen will generate types which provide union-like access to structure fields.
If the target Rust version does not support the new `union` type or there is a field that cannot derive `Copy`, then bindgen will provide union-like access to a `struct`.

Interacting with these unions is slightly different than the new `union` types. Whenever a variant of the union is accessed, it must be done through a reference.
Interacting with these unions is slightly different than the new `union` types.
You must access union variants through a reference.

```rust,ignore
mod bindings;
fn stable() {
fn bindgenunion() {
// `default()` or `zeroed()` may still be used with Bindgen's Union types
let mut x = bindings::greek_t::default();
Expand All @@ -116,7 +122,7 @@ fn stable() {
}
```

If you attempt to access a BindgenUnion field directly, you will see errors like this:
If you attempt to access a `BindgenUnion` field directly, you will see errors like this:

```text
error[E0308]: mismatched types
Expand Down
6 changes: 4 additions & 2 deletions src/options.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ where
I: Iterator<Item = String>,
{
let rust_target_help = format!(
"Version of the Rust compiler to target. Valid options are: {:?}.",
RUST_TARGET_STRINGS);
"Version of the Rust compiler to target. Valid options are: {:?}. Defaults to {:?}.",
RUST_TARGET_STRINGS,
String::from(RustTarget::default()),
);

let matches = App::new("bindgen")
.version(env!("CARGO_PKG_VERSION"))
Expand Down

0 comments on commit 074f1f1

Please sign in to comment.