| # 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() { |
| // Initialize 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 initialize 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` |
| ``` |