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;
--rust-target
--with-derive-default
Bindgen can emit one of two Rust types that correspond to C unions:
union
builtin (only available in Rust >= 1.19, including nightly)BindgenUnion
(available for all Rust targets)Bindgen uses the following logic to determine which Rust union type to emit:
Copy
, then generate a union
builtin.BindgenUnion
.union
builtinWhen using the union
builtin type, there are two choices for initialization:
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 } } }
BindgenUnion
typeIf 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`