• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Using the Union Types Generated by Bindgen
2
3**NOTE**: Rust 1.19 stabilized the `union` type (see Rust issue [#32836](https://github.com/rust-lang/rust/issues/32836)).
4
5You can pass the `--rust-target` option to tell `bindgen` to target a specific version of Rust.
6By default, `bindgen` will target the latest stable Rust.
7The `--rust-target` option accepts a specific stable version (such as "1.0" or "1.19") or "nightly".
8
9**NOTE**: The `--unstable-rust` option is deprecated; use `--rust-target nightly` instead.
10
11In general, most interactions with unions (either reading or writing) are unsafe, meaning you must surround union accesses in an `unsafe {}` block.
12
13For this discussion, we will use the following C type definitions:
14
15```c
16typedef struct {
17    int32_t a;
18    int32_t b;
19} alpha_t;
20
21typedef struct {
22    uint32_t c;
23    uint16_t d;
24    uint16_t e;
25    uint8_t  f;
26} beta_t;
27
28typedef union {
29    alpha_t alfa;
30    beta_t  bravo;
31} greek_t;
32```
33
34## Relevant Bindgen Options
35
36### Library
37
38* [`bindgen::Builder::rust_target()`](https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.rust_target) <!-- Update when live -->
39* [`bindgen::Builder::derive_default()`](https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.derive_default)
40
41### Command Line
42
43* `--rust-target`
44* `--with-derive-default`
45
46## Which union type will Bindgen generate?
47
48Bindgen can emit one of two Rust types that correspond to C unions:
49
50* Rust's `union` builtin (only available in Rust >= 1.19, including nightly)
51* Bindgen's `BindgenUnion` (available for all Rust targets)
52
53Bindgen uses the following logic to determine which Rust union type to emit:
54
55* If the Rust target is >= 1.19 (including nightly) AND each field of the union can derive `Copy`, then generate a `union` builtin.
56* Otherwise, generate a `BindgenUnion`.
57
58## Using the `union` builtin
59
60When using the `union` builtin type, there are two choices for initialization:
61
621. Zero
632. With a specific variant
64
65```rust,ignore
66mod bindings_builtin_union;
67
68fn union_builtin() {
69    // Initalize the union to zero
70    let x = bindings_builtin_union::greek_t::default();
71
72    // If `--with-derive-default` option is not used, the following may be used
73    //   to initalize the union to zero:
74    let x = unsafe { std::mem::zeroed::<bindings_builtin_union::greek_t>() };
75
76    // Or, it is possible to initialize exactly one variant of the enum:
77    let x = bindings_builtin_union::greek_t {
78        alfa: bindings_builtin_union::alpha_t {
79            a: 1,
80            b: -1,
81        },
82    };
83
84    unsafe {
85        println!("{:?}", z.alfa);  // alpha_t { a: 1, b: -1 }
86        println!("{:?}", z.bravo); // beta_t { c: 1, d: 65535, e: 65535, f: 127 }
87    }
88}
89```
90
91## Using the `BindgenUnion` type
92
93If 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`.
94
95Interacting with these unions is slightly different than the new `union` types.
96You must access union variants through a reference.
97
98```rust,ignore
99mod bindings;
100
101fn bindgenunion() {
102    // `default()` or `zeroed()` may still be used with Bindgen's Union types
103    let mut x = bindings::greek_t::default();
104
105    // This will not work:
106    // let x = bindings::greek_t {
107    //     alfa: bindings::alpha_t {
108    //         a: 1,
109    //         b: -1,
110    //     },
111    // };
112
113    // Instead, access the field through `.as_ref()` and `.as_mut()` helpers:
114    unsafe {
115        *x.alfa.as_mut() = bindings::alpha_t {
116            a: 1,
117            b: -1,
118        };
119
120        println!("{:?}", x.alfa.as_ref());  // alpha_t { a: 1, b: -1 }
121        println!("{:?}", x.bravo.as_ref()); // beta_t { c: 1, d: 65535, e: 65535, f: 0 }
122    }
123```
124
125If you attempt to access a `BindgenUnion` field directly, you will see errors like this:
126
127```text
128error[E0308]: mismatched types
129  --> src/main.rs:44:15
130   |
13144 |           alfa: bindings::alpha_t {
132   |  _______________^
13345 | |             a: 1,
13446 | |             b: -1,
13547 | |         },
136   | |_________^ expected struct `bindings::__BindgenUnionField`, found struct `bindings::alpha_t`
137   |
138   = note: expected type `bindings::__BindgenUnionField<bindings::alpha_t>`
139              found type `bindings::alpha_t`
140```
141