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

By using the flag `--unstable-rust`, bindgen will generate the preliminary unstable `union` type.

In general, most interactions with unions (either reading or writing) are unsafe.

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

```c
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::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)

### Command Line

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

## Using the unstable `union` version

With `struct`s generated by bindgen from C, it is possible to initialize fields in a "normal" rust way:

```rust,ignore
mod bindings;

fn main() {
    let x = bindings::alpha_t {
        a: 1,
        b: -1,
    };
}
```

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

```rust,ignore
#![feature(untagged_unions)]
mod bindings_unstable;

fn unstable() {
    // Initalize the union to zero
    let x = bindings_unstable::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>() };

    // Or, it is possible to initialize exactly one variant of the enum:
    let x = bindings_unstable::greek_t {
        alfa: bindings_unstable::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 stable BindgenUnion types

For versions of Rust that do not support the new `union` type, bindgen will generate types which provide union-like access to structure fields.

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.

```rust,ignore
mod bindings;

fn stable() {
    // `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:

```text
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`
```
