summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--book/src/SUMMARY.md1
-rw-r--r--book/src/using-unions.md132
2 files changed, 133 insertions, 0 deletions
diff --git a/book/src/SUMMARY.md b/book/src/SUMMARY.md
index 1a1818f8..43d227c0 100644
--- a/book/src/SUMMARY.md
+++ b/book/src/SUMMARY.md
@@ -18,3 +18,4 @@
- [Replacing One Type with Another](./replacing-types.md)
- [Preventing the Derivation of `Copy` and `Clone`](./nocopy.md)
- [Generating Bindings to C++](./cpp.md)
+- [Using Unions](./using-unions.md)
diff --git a/book/src/using-unions.md b/book/src/using-unions.md
new file mode 100644
index 00000000..66ba6d13
--- /dev/null
+++ b/book/src/using-unions.md
@@ -0,0 +1,132 @@
+# Using the Union Types Generated by Bindgen
+
+**NOTE:** As of Rust version 1.17, Rust does not have a stable `union` type. Issue [#32836](https://github.com/rust-lang/rust/issues/32836) tracks the stabilization of a `union` type in Rust. By default, bindgen will generate the preliminary unstable `union` type, unless the flag `--no-unstable-rust` flag is used.
+
+In general, most interactions with unions (either reading or writing) are unsafe.
+
+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::no_unstable_rust()`](https://docs.rs/bindgen/0.25.3/bindgen/struct.Builder.html#method.no_unstable_rust)
+* [`bindgen::Builder::derive_default()`](https://docs.rs/bindgen/0.25.3/bindgen/struct.Builder.html#method.derive_default)
+
+### Command Line
+
+* `--no-unstable-rust`
+* `--with-derive-default`
+
+## Using the unstable `union` version
+
+With `struct`s generated by bindgen from C, it is possible to initialize fields in a "normal" rust way:
+
+```rust,ignore
+mod bindings;
+
+fn main() {
+ let x = bindings::alpha_t {
+ a: 1,
+ b: -1,
+ };
+}
+```
+
+When using the unstable `union` type, there are two choices for initialization: Zeroed, and with a specific variant.
+
+```rust,ignore
+#![feature(untagged_unions)]
+mod bindings_unstable;
+
+fn unstable() {
+ // Initalize the union to zero
+ let x = bindings_unstable::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_unstable::greek_t>() };
+
+ // Or, it is possible to initialize exactly one variant of the enum:
+ let x = bindings_unstable::greek_t {
+ alfa: bindings_unstable::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 stable BindgenUnion types
+
+For versions of Rust that do not support the new `union` type, bindgen will generate types which provide union-like access to structure fields.
+
+Interacting with these unions is slightly different than the new `union` types. Whenever a variant of the union is accessed, it must be done through a reference.
+
+```rust,ignore
+mod bindings;
+
+fn stable() {
+ // `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`
+``` \ No newline at end of file