cbindgen 0.10.1

A tool for generating C bindings to Rust code.
# cbindgen User Guide

cbindgen creates C/C++11 headers for Rust libraries which expose a public C API.

While you could do this by hand, it's not a particularly good use of your time. It's also much more likely to be error-prone than machine-generated headers that are based on your actual Rust code. The cbindgen developers have also worked closely with the developers of Rust to ensure that the headers we generate reflect actual guarantees about Rust's type layout and ABI.

C++ headers are nice because we can use operator overloads, constructors, enum classes, and templates to make the API more ergonomic and Rust-like. C headers are nice because you can be more confident that whoever you're interoperating with can handle them. With cbindgen *you don't need to choose*! You can just tell it to emit both from the same Rust library.

There are two ways to use cbindgen: as a standalone program, or as a library (presumably in your build.rs).
There isn't really much practical difference, because cbindgen is a simple rust library with no interesting dependencies. Using it as a program means people building your software will need it installed. Using it in your library means people may have to build cbindgen more frequently (e.g. every time they update their rust compiler).

It's worth noting that the development of cbindgen has been largely adhoc, as features have been added to support the usecases of the maintainers. This means cbindgen may randomly fail to support some particular situation simply because no one has put in the effort to handle it yet. [Please file an issue if you run into such a situation][file-it]. Although since we all have other jobs, you might need to do the implementation work too :)





# Quick Start

To install cbindgen, you just need to run

```text
cargo install --force cbindgen
```

(--force just makes it update to the latest cbindgen if it's already installed)

To use cbindgen you need two things:

* A configuration (cbindgen.toml, which can be empty to start)
* A Rust crate with a public C API

Then all you need to do is run it:

```text
cbindgen --config cbindgen.toml --crate my_rust_library --output my_header.h
```

See `cbindgen --help` for more options.

[Get a template cbindgen.toml here.](template.toml)



## build.rs

If you don't want to use cbindgen as an application, here's an example build.rs script:

```rust
extern crate cbindgen;

use std::env;

fn main() {
    let crate_dir = env::var("CARGO_MANIFEST_DIR").unwrap();

    cbindgen::Builder::new()
      .with_crate(crate_dir)
      .generate()
      .expect("Unable to generate bindings")
      .write_to_file("bindings.h");
}
```

You can add configuration options using the [`Builder`](https://docs.rs/cbindgen/*/cbindgen/struct.Builder.html#methods) interface.

If you'd like to use a `build.rs` script with a `cbindgen.toml`, consider using [`cbindgen::generate()`](https://docs.rs/cbindgen/*/cbindgen/fn.generate.html) instead.





# Writing Your C API

cbindgen has a simple but effective strategy. It walks through your crate looking for:

* `#[no_mangle] pub extern fn` ("functions")
* `#[no_mangle] pub static` ("globals")
* `pub const` ("constants")

and generates a header declaring those items. But to declare those items, it needs to also be able to describe the layout and ABI of the types that appear in their signatures. So it will also spider through your crate (and optionally its dependencies) to try to find the definitions of every type used in your public API.

> 🚨 NOTE: A major limitation of cbindgen is that it does not understand Rust's module system or namespacing. This means that if cbindgen sees that it needs the definition for `MyType` and there exists two things in your project with the type name `MyType`, it won't know what to do. Currently, cbindgen's behaviour is unspecified if this happens. However this may be ok if they have [different cfgs][section-cfgs].

If a type is determined to have a guaranteed layout, a full definition will be emitted in the header. If the type doesn't have a guaranteed layout, only a forward declaration will be emitted. This may be fine if the type is intended to be passed around opaquely and by reference.




# Examples

🚧 🏗

It would be really nice to have some curated and clean examples, but we don't have those yet.

[The README has some useful links though](README.md#examples).



# Supported Types

Most things in Rust don't have a guaranteed layout by default. In most cases this is nice because it enables layout to be optimized in the majority of cases where type layout isn't that interesting. However this is problematic for our purposes. Thankfully Rust lets us opt into guaranteed layouts with the `repr` attribute.

You can learn about all of the different repr attributes [by reading Rust's reference][reference], but here's a quick summary:

* `#[repr(C)]`: give this struct/union/enum the same layout and ABI C would
* `#[repr(u8, u16, ... etc)]`: give this enum the same layout and ABI as the given integer type
* `#[repr(transparent)]`: give this single-field struct the same ABI as its field (useful for newtyping integers but keeping the integer ABI)

cbindgen does not currently support the align or packed reprs.

However it *does* support using `repr(C)`/`repr(u8)` on non-C-like enums (enums with fields). This gives a C-compatible tagged union layout, as [defined by this RFC 2195][really-tagged-unions]. `repr(C)` will give a simpler layout that is perhaps more intuitive, while `repr(u8)` will produce a more compact layout.

If you ensure everything has a guaranteed repr, then cbindgen will generate definitions for:

* struct (named-style or tuple-style)
* enum (fieldless or with fields)
* union
* type
* `[T; n]` (arrays always have a guaranteed C-compatible layout)
* `&T`, `&mut T`, `*const T`, `*mut T`, `Option<&T>`, `Option<&mut T>` (all have the same pointer ABI)
* `fn()` (as an actual function pointer)
* `bitflags! { ... }` (if macro_expansion.bitflags is enabled)

structs, enums, unions, and type aliases may be generic, although certain generic substitutions may fail to resolve under certain configurations. In C mode generics are resolved through monomorphization and mangling, while in C++ mode generics are resolved with templates. cbindgen cannot support generic functions, as they do not actually have a single defined symbol.

cbindgen sadly cannot ever support anonymous tuples `(A, B, ...)`, as there is no way to guarantee their layout. You must use a tuple struct.

cbindgen also cannot support wide pointers like `&dyn Trait` or `&[T]`, as their layout and ABI is not guaranteed. In the case of slices you can at least decompose them into a pointer and length, and reconstruct them with `slice::from_raw_parts`.

If cbindgen determines that a type is zero-sized, it will erase all references to that type (so fields of that type simply won't be emitted). This won't work if that type appears as a function argument because C, C++, and Rust all have different definitions of what it means for a type to be empty.

Don't use the `[u64; 0]` trick to over-align a struct, we don't support this.

cbindgen contains the following hardcoded mappings (again completely ignoring namespacing, literally just looking at the name of the type):




## std types

* bool => bool
* char => char32_t
* u8 => uint8_t
* u16 => uint16_t
* u32 => uint32_t
* u64 => uint64_t
* usize => uintptr_t
* i8 => int8_t
* i16 => int16_t
* i32 => int32_t
* i64 => int64_t
* isize => intptr_t
* f32 => float
* f64 => double
* VaList => va_list
* PhantomData => *evaporates*, can only appear as the field of a type
* () => *evaporates*, can only appear as the field of a type



## libc types

* c_void => void
* c_char => char
* c_schar => signed char
* c_uchar => unsigned char
* c_float => float
* c_double => double
* c_short => short
* c_int => int
* c_long => long
* c_longlong => long long
* c_ushort => unsigned short
* c_uint => unsigned int
* c_ulong => unsigned long
* c_ulonglong => unsigned long long



## stdint types

* uint8_t => uint8_t
* uint16_t => uint16_t
* uint32_t => uint32_t
* uint64_t => uint64_t
* uintptr_t => uintptr_t
* size_t => size_t
* int8_t => int8_t
* int16_t => int16_t
* int32_t => int32_t
* int64_t => int64_t
* intptr_t => intptr_t
* ssize_t => ssize_t
* ptrdiff_t => ptrdiff_t






# Configuring Your Header

cbindgen supports several different options for configuring the output of your header, including target language, styling, mangling, prefixing, includes, and defines.





## Defines and Cfgs

As cbindgen spiders through your crate, it will make note of all the cfgs it found on the path to every item. If it finds multiple declarations that share a single name but have different cfgs, it will then try to emit every version it found wrapped in defines that correspond to those cfgs. In this way platform-specific APIs or representations can be properly supported.

However cbindgen has no way of knowing how you want to map those cfgs to defines. You will need to use the `[defines]` section in your cbindgen.toml to specify all the different mappings. It natively understands concepts like any() and all(), so you only need to tell it how you want to translate base concepts like `target_os = "freebsd"` or `feature = "serde"`.

Note that because cbindgen just parses the source of your crate, you mostly don't need to worry about what crate features or what platform you're targetting. Every possible configuration should be visible to the parser. Our primitive mappings should also be completely platform agnostic (i32 is int32_t regardless of your target).

While modules within a crate form a tree with uniquely defined paths to each item, and therefore uniquely defined cfgs for those items, dependencies do not. If you depend on a crate in multiple ways, and those ways produce different cfgs, one of them will be arbitrarily chosen for any types found in that crate.




## Annotations

While output configuration is primarily done through the cbindgen.toml, in some cases you need to manually override your global settings. In those cases you can add inline annotations to your types, which are doc comments that start with `cbindgen:`. Here's an example of using annotations to rename a struct's fields and opt into overloading `operator==`:

```rust
/// cbindgen:field-names=[x, y]
/// cbindgen:derive-eq
#[repr(C)]
pub struct Point(pub f32, pub f32);
```

An annotation may be a bool, string (no quotes), or list of strings. If just the annotation's name is provided, `=true` is assumed. The annotation parser is currently fairly naive and lacks any capacity for escaping, so don't try to make any strings with `=`, `,`, `[` or `]`.

Most annotations are just local overrides for identical settings in the cbindgen.toml, but a few are unique because they don't make sense in a global context. The set of supported annotation are as follows:



### Struct Annotations

* field-names=\[field1, field2, ...\] -- sets the names of all the fields in the output struct. These names will be output verbatim, and are not eligible for renaming.

The rest are just local overrides for the same options found in the cbindgen.toml:

* rename-all=RenameRule
* derive-constructor
* derive-eq
* derive-neq
* derive-lt
* derive-lte
* derive-gt
* derive-gte



### Enum Annotations

* enum-trailing-values=\[variant1, variant2, ...\] -- add the following fieldless enum variants to the end of the enum's definition. These variant names *will* have the enum's renaming rules applied.

WARNING: if any of these values are ever passed into Rust, behaviour will be Undefined. Rust does not know about them, and will assume they cannot happen.

The rest are just local overrides for the same options found in the cbindgen.toml:

* rename-all=RenameRule
* add-sentinel
* derive-helper-methods
* derive-const-casts
* derive-mut-casts
* derive-tagged-enum-destructor
* derive-tagged-enum-copy-constructor
* prefix-with-name
* private-default-tagged-enum-constructor



### Union Annotations

* field-names=\[field1, field2, ...\] -- sets the names of all the fields in the output union. These names will be output verbatim, and are not eligible for renaming.

The rest are just local overrides for the same options found in the cbindgen.toml:

* rename-all=RenameRule



### Function Annotations

All function attributes are just local overrides for the same options found in the cbindgen.toml:

* rename-all=RenameRule
* prefix
* postfix




## cbindgen.toml

Most configuration happens through your cbindgen.toml file. Every value has a default (that is usually reasonable), so you can start with an empty cbindgen.toml and tweak it until you like the output you're getting.

Note that many options defined here only apply for one of C or C++. Usually it's an option specifying whether we should try to make use of a feature in C++'s type system or generate a helper method.

```toml
# The language to output bindings in
#
# possible values: "C", "C++"
#
# default: "C++"
language = "C"




# Options for wrapping the contents of the header:

# An optional string of text to output at the beginning of the generated file
# default: doesn't emit anything
header = "/* Text to put at the beginning of the generated file. Probably a license. */"

# An optional string of text to output at the end of the generated file
# default: doesn't emit anything
trailer = "/* Text to put at the end of the generated file */"

# An optional name to use as an include guard
# default: doesn't emit an include guard
include_guard = "mozilla_wr_bindings_h"

# An optional string of text to output between major sections of the generated
# file as a warning against manual editing
#
# default: doesn't emit anything
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"

# Whether to include a comment with the version of cbindgen used to generate the file
# default: false
include_version = true

# An optional namespace to output around the generated bindings
# default: doesn't emit a namespace
namespace = "ffi"

# An optional list of namespaces to output around the generated bindings
# default: []
namespaces = ["mozilla", "wr"]

# An optional list of namespaces to declare as using with "using namespace"
# default: []
using_namespaces = ["mozilla", "wr"]

# A list of sys headers to #include (with angle brackets)
# default: []
sys_includes = ["stdio", "string"]

# A list of headers to #include (with quotes)
# default: []
includes = ["my_great_lib.h"]

# Whether cbindgen's default C/C++ standard imports should be suppressed. These
# imports are included by default because our generated headers tend to require
# them (e.g. for uint32_t). Currently, the generated imports are:
#
# * for C: <stdarg.h>, <stdbool.h>, <stdint.h>, <stdlib.h>, <uchar.h>
#
# * for C++: <cstdarg>, <cstdint>, <cstdlib>, <new>, <cassert> (depending on config)
#
# default: false
no_includes = false





# Code Style Options

# The style to use for curly braces
#
# possible values: "SameLine", "NextLine"
#
# default: "SameLine"
braces = "SameLine"

# The desired length of a line to use when formatting lines
# default: 100
line_length = 80

# The amount of spaces to indent by
# default: 2
tab_width = 3

# How the generated documentation should be commented.
#
# possible values:
# * "c": /* like this */
# * "c99": // like this
# * "c++": /// like this
# * "doxy": like C, but with leading *'s on each line
# * "auto": "c++" if that's the language, "doxy" otherwise
#
# default: "auto"
documentation_style = "doxy"





# Codegen Options

# When generating a C header, the kind of declaration style to use for structs
# or enums.
#
# possible values:
# * "type": typedef struct { ... } MyType;
# * "tag": struct MyType { ... };
# * "both": typedef struct MyType { ... } MyType;
#
# default: "both"
style = "both"

# A list of substitutions for converting cfg's to ifdefs. cfgs which aren't
# defined here will just be discarded.
#
# e.g.
# `#[cfg(target = "freebsd")] ...`
# becomes
# `#if defined(DEFINE_FREEBSD) ... #endif`
[defines]
"target_os = freebsd" = "DEFINE_FREEBSD"
"feature = serde" = "DEFINE_SERDE"





[export]
# A list of additional items to always include in the generated bindings if they're
# found but otherwise don't appear to be used by the public API.
#
# default: []
include = ["MyOrphanStruct", "MyGreatTypeRename"]

# A list of items to not include in the generated bindings
# default: []
exclude = ["Bad"]

# A prefix to add before the name of every item
# default: no prefix is added
prefix = "CAPI_"

# Types of items that we'll generate. If empty, then all types of item are emitted.
#
# possible items: (TODO: explain these in detail)
# * "constants":
# * "globals":
# * "enums":
# * "structs":
# * "unions":
# * "typedefs":
# * "opaque":
# * "functions":
#
# default: []
item_types = ["enums", "structs", "opaque", "functions"]

# Whether applying rules in export.rename prevents export.prefix from applying.
#
# e.g. given this toml:
#
# [export]
# prefix = "capi_"
# [export.rename]
# "MyType" = "my_cool_type"
#
# You get the following results:
#
# renaming_overrides_prefixing = true:
# "MyType" => "my_cool_type"
#
# renaming_overrides_prefixing = false:
# "MyType => capi_my_cool_type"
#
# default: false
renaming_overrides_prefixing = true

# Table of name conversions to apply to item names (lhs becomes rhs)
[export.rename]
"MyType" = "my_cool_type"
"my_function" = "BetterFunctionName"

# Table of things to add to the body of any struct, union, or enum that has the
# given name. This can be used to add things like methods which don't change ABI.
[export.body]
"MyType" = """
  void cppMethod() const;
"""





[fn]
# An optional prefix to put before every function declaration
# default: no prefix added
prefix = "WR_START_FUNC"

# An optional postfix to put after any function declaration
# default: no postix added
postfix = "WR_END_FUNC"

# How to format function arguments
#
# possible values:
# * "horizontal": place all arguments on the same line
# * "vertical": place each argument on its own line
# * "auto": only use vertical if horizontal would exceed line_length
#
# default: "auto"
args = "horizontal"

# An optional string that should prefix function declarations which have been
# marked as `#[must_use]`. For instance, "__attribute__((warn_unused_result))"
# would be a reasonable value if targeting gcc/clang. A more portable solution
# would involve emitting the name of a macro which you define in a
# platform-specific way. e.g. "MUST_USE_FUNC"
# default: nothing is emitted for must_use functions
must_use = "MUST_USE_FUNC"

# A rule to use to rename function argument names. The renaming assumes the input
# is the Rust standard snake_case, however it accepts all the different rename_args
# inputs. This means many options here are no-ops or redundant.
#
# possible values (that actually do something):
# * "CamelCase": my_arg => myArg
# * "PascalCase": my_arg => MyArg
# * "GeckoCase": my_arg => aMyArg
# * "ScreamingSnakeCase": my_arg => MY_ARG
# * "None": apply no renaming
#
# technically possible values (that shouldn't have a purpose here):
# * "SnakeCase": apply no renaming
# * "LowerCase": apply no renaming (actually applies to_lowercase, is this bug?)
# * "UpperCase": same as ScreamingSnakeCase in this context
# * "QualifiedScreamingSnakeCase" => same as ScreamingSnakeCase in this context
#
# default: "None"
rename_args = "PascalCase"





[struct]
# A rule to use to rename struct field names. The renaming assumes the input is
# the Rust standard snake_case, however it acccepts all the different rename_args
# inputs. This means many options here are no-ops or redundant.
#
# possible values (that actually do something):
# * "CamelCase": my_arg => myArg
# * "PascalCase": my_arg => MyArg
# * "GeckoCase": my_arg => mMyArg
# * "ScreamingSnakeCase": my_arg => MY_ARG
# * "None": apply no renaming
#
# technically possible values (that shouldn't have a purpose here):
# * "SnakeCase": apply no renaming
# * "LowerCase": apply no renaming (actually applies to_lowercase, is this bug?)
# * "UpperCase": same as ScreamingSnakeCase in this context
# * "QualifiedScreamingSnakeCase" => same as ScreamingSnakeCase in this context
#
# default: "None"
rename_fields = "PascalCase"

# An optional string that should come before the name of any struct which has been
# marked as `#[must_use]`. For instance, "__attribute__((warn_unused))"
# would be a reasonable value if targeting gcc/clang. A more portable solution
# would involve emitting the name of a macro which you define in a
# platform-specific way. e.g. "MUST_USE_STRUCT"
#
# default: nothing is emitted for must_use structs
must_use = "MUST_USE_STRUCT"

# Whether a Rust type with associated consts should emit those consts inside the
# type's body. Otherwise they will be emitted trailing and with the type's name
# prefixed. This does nothing if the target is C, or if
# [const]allow_static_const = false
#
# default: false
# associated_constants_in_body: false

# Whether to derive a simple constructor that takes a value for every field.
# default: false
derive_constructor = true

# Whether to derive an operator== for all structs
# default: false
derive_eq = false

# Whether to derive an operator!= for all structs
# default: false
derive_neq = false

# Whether to derive an operator< for all structs
# default: false
derive_lt = false

# Whether to derive an operator<= for all structs
# default: false
derive_lte = false

# Whether to derive an operator> for all structs
# default: false
derive_gt = false

# Whether to derive an operator>= for all structs
# default: false
derive_gte = false





[enum]
# A rule to use to rename enum variants, and the names of any fields those
# variants have. This should probably be split up into two separate options, but
# for now, they're the same! See the documentation for `[struct]rename_fields`
# for how this applies to fields. Renaming of the variant assumes that the input
# is the Rust standard PascalCase. In the case of QualifiedScreamingSnakeCase,
# it also assumed that the enum's name is PascalCase.
#
# possible values (that actually do something):
# * "CamelCase": MyVariant => myVariant
# * "SnakeCase": MyVariant => my_variant
# * "ScreamingSnakeCase": MyVariant => MY_VARIANT
# * "QualifiedScreamingSnakeCase": MyVariant => ENUM_NAME_MY_VARIANT
# * "LowerCase": MyVariant => myvariant
# * "UpperCase": MyVariant => MYVARIANT
# * "None": apply no renaming
#
# technically possible values (that shouldn't have a purpose for the variants):
# * "PascalCase": apply no renaming
# * "GeckoCase": apply no renaming
#
# default: "None"
rename_variants = "None"

# Whether an extra "sentinel" enum variant should be added to all generated enums.
# Firefox uses this for their IPC serialization library.
#
# WARNING: if the sentinel is ever passed into Rust, behaviour will be Undefined.
# Rust does not know about this value, and will assume it cannot happen.
#
# default: false
add_sentinel = false

# Whether enum variant names should be prefixed with the name of the enum.
# default: false
prefix_with_name = false

# Whether to generate static `::MyVariant(..)` constructors and `bool IsMyVariant()`
# methods for enums with fields.
#
# default: false
derive_helper_methods = false

# Whether to generate `const MyVariant& AsMyVariant() const` methods for enums with fields.
# default: false
derive_const_casts = false

# Whether to generate `MyVariant& AsMyVariant()` methods for enums with fields
# default: false
derive_mut_casts = false

# The name of the macro/function to use for asserting `IsMyVariant()` in the body of
# derived `AsMyVariant()` cast methods.
#
# default: "assert" (but also causes `<cassert>` to be included by default)
cast_assert_name = "MOZ_RELEASE_ASSERT"

# An optional string that should come before the name of any enum which has been
# marked as `#[must_use]`. For instance, "__attribute__((warn_unused))"
# would be a reasonable value if targeting gcc/clang. A more portable solution
# would involve emitting the name of a macro which you define in a
# platform-specific way. e.g. "MUST_USE_ENUM"
#
# Note that this refers to the *output* type. That means this will not apply to an enum
# with fields, as it will be emitted as a struct. `[struct]must_use` will apply there.
#
# default: nothing is emitted for must_use enums
must_use = "MUST_USE_ENUM"

# Whether enums with fields should generate destructors. This exists so that generic
# enums can be properly instantiated with payloads that are C++ types with
# destructors. This isn't necessary for structs because C++ has rules to
# automatically derive the correct constructors and destructors for those types.
#
# Care should be taken with this option, as Rust and C++ cannot
# properly interoperate with eachother's notions of destructors. Also, this may
# change the ABI for the type. Either your destructor-full enums must live
# exclusively within C++, or they must only be passed by-reference between
# C++ and Rust.
#
# default: false
derive_tagged_enum_destructor = false

# Whether enums with fields should generate copy-constructor. See the discussion on
# derive_tagged_enum_destructor for why this is both useful and very dangerous.
#
# default: false
derive_tagged_enum_copy_constructor = false

# Whether enums with fields should generate an empty, private destructor.
# This allows the auto-generated constructor functions to compile, if there are
# non-trivially constructible members. This falls in the same family of
# dangerousness as `derive_tagged_enum_copy_constructor` and co.
#
# default: false
private_default_tagged_enum_constructor = false





[const]
# Whether a generated constant can be a static const in C++ mode. I have no
# idea why you would turn this off.
#
# default: true
allow_static_const = true





[macro_expansion]
# Whether bindings should be generated for instances of the bitflags! macro.
# default: false
bitflags = true






# Options for how your Rust library should be parsed

[parse]
# Whether to parse dependent crates and include their types in the output
# default: false
parse_deps = true

# A white list of crate names that are allowed to be parsed. If this is defined,
# only crates found in this list will ever be parsed.
#
# default: there is no whitelist (NOTE: this is the opposite of [])
include = ["webrender", "webrender_traits"]

# A black list of crate names that are not allowed to be parsed.
# default: []
exclude = ["libc"]

# Whether to use a new temporary target directory when running `rustc --pretty=expanded`.
# This may be required for some build processes.
#
# default: false
clean = false

# Which crates other than the top-level binding crate we should generate
# bindings for.
#
# default: []
extra_bindings = ["my_awesome_dep"]

[parse.expand]
# A list of crate names that should be run through `cargo expand` before
# parsing to expand any macros. Note that if a crate is named here, it
# will always be parsed, even if the blacklist/whitelist says it shouldn't be.
#
# default: []
crates = ["euclid"]

# If enabled,  use the `--all-features` option when expanding. Ignored when
# `features` is set. For backwards-compatibility, this is forced on if
# `expand = ["euclid"]` shorthand is used.
#
# default: false
all_features = false

# When `all_features` is disabled and this is also disabled, use the
# `--no-default-features` option when expanding.
#
# default: true
default_features = true

# A list of feature names that should be used when running `cargo expand`. This
# combines with `default_features` like in your `Cargo.toml`. Note that the features
# listed here are features for the current crate being built, *not* the crates
# being expanded. The crate's `Cargo.toml` must take care of enabling the
# appropriate features in its dependencies
#
# default: []
features = ["cbindgen"]

```





[reference]: https://doc.rust-lang.org/nightly/reference/type-layout.html#representations
[really-tagged-unions]: https://github.com/rust-lang/rfcs/blob/master/text/2195-really-tagged-unions.md
[section-cfgs]: #defines-and-cfgs
[file-it]: https://github.com/eqrion/cbindgen/issues/new