1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
|
# Using the Union Types Generated by Bindgen
**NOTE**: Rust 1.19 stabilized the `union` type (see Rust issue [#32836](https://github.com/rust-lang/rust/issues/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:
```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::rust_target()`](https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.rust_target) <!-- Update when live -->
* [`bindgen::Builder::derive_default()`](https://docs.rs/bindgen/latest/bindgen/struct.Builder.html#method.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
```rust,ignore
mod bindings_builtin_union;
fn union_builtin() {
// Initalize 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 initalize 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.
```rust,ignore
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:
```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`
```
|