# 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) * [`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::() }; // 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` found type `bindings::alpha_t` ```