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