Using Unions - The bindgen User Guide
Description: `bindgen` automatically generates Rust FFI bindings to C and C++ libraries.

## Keyboard shortcuts

Press `←` or `→` to navigate between chapters

Press `S` or `/` to search in the book

Press `?` to show this help

Press `Esc` to hide this help

# Using the Union Types Generated by Bindgen

NOTE: Rust 1.19 stabilized the `union` type (see Rust issue #32836).

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”.

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:

    typedef struct {
        int32_t a;
        int32_t b;
    } alpha_t;

    typedef struct {
        uint32_t c;
        uint16_t d;
        uint16_t e;
        uint8_t  f;
    } beta_t;

    typedef union {
        alpha_t alfa;
        beta_t  bravo;
    } greek_t;

## Relevant Bindgen Options

### Library

- `bindgen::Builder::rust_target()`
- `bindgen::Builder::derive_default()`

### Command Line

- `--rust-target`
- `--with-derive-default`

## Which union type will Bindgen generate?

Bindgen can emit one of two Rust types that correspond to C unions:

- Rust’s `union` builtin (only available in Rust >= 1.19, including nightly)
- Bindgen’s `BindgenUnion` (available for all Rust targets)

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:

1. Zero
2. With a specific variant

    mod bindings_builtin_union;

    fn union_builtin() {
        // Initialize the union to zero
        let x = bindings_builtin_union::greek_t::default();

        // If `--with-derive-default` option is not used, the following may be used
        //   to initialize the union to zero:
        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_builtin_union::greek_t {
            alfa: bindings_builtin_union::alpha_t {
                a: 1,
                b: -1,
            },
        };

        unsafe {
            println!("{:?}", z.alfa);  // alpha_t { a: 1, b: -1 }
            println!("{:?}", z.bravo); // beta_t { c: 1, d: 65535, e: 65535, f: 127 }
        }
    }

## Using the `BindgenUnion` type

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. You must access union variants through a reference.

    mod bindings;

    fn bindgenunion() {
        // `default()` or `zeroed()` may still be used with Bindgen's Union types
        let mut x = bindings::greek_t::default();

        // This will not work:
        // let x = bindings::greek_t {
        //     alfa: bindings::alpha_t {
        //         a: 1,
        //         b: -1,
        //     },
        // };

        // Instead, access the field through `.as_ref()` and `.as_mut()` helpers:
        unsafe {
            *x.alfa.as_mut() = bindings::alpha_t {
                a: 1,
                b: -1,
            };

            println!("{:?}", x.alfa.as_ref());  // alpha_t { a: 1, b: -1 }
            println!("{:?}", x.bravo.as_ref()); // beta_t { c: 1, d: 65535, e: 65535, f: 0 }
        }

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

    error[E0308]: mismatched types
      --> src/main.rs:44:15
       |
    44 |           alfa: bindings::alpha_t {
       |  _______________^
    45 | |             a: 1,
    46 | |             b: -1,
    47 | |         },
       | |_________^ expected struct `bindings::__BindgenUnionField`, found struct `bindings::alpha_t`
       |
       = note: expected type `bindings::__BindgenUnionField<bindings::alpha_t>`
                  found type `bindings::alpha_t`