Skip to content

Repository files navigation

Rust bindgen helpers

GitHub repo crates.io version crate usage docs.rs status crates.io license CI build status Codecov

Utilities for shaping Rust code generated from C headers with bindgen. This crate re-exports bindgen and adds a small wrapper for common cleanup tasks: renaming generated items, rustifying and renaming C enums, applying regex removals and case conversion to identifiers, and collecting matching integer #define constants into additional Rust enums.

The lower-level Renamer type implements bindgen parse callbacks directly for existing bindgen-style build scripts. For new code, BindingsBuilder wraps an already configured bindgen Builder, installs the callbacks, runs generation, and writes the final bindings with any helper-generated enums appended.

Usage

# Cargo.toml
[build-dependencies]
# Bindgen_helpers re-exports all of bindgen's public API at the root level
# Do not use bindgen directly to avoid some version conflicts
bindgen_helpers = "0.3"
// build.rs
use bindgen_helpers::{BindingsBuilder, Builder, define_enum, rename_enum};

fn main() {
  let builder = Builder::default()
    // in real code, use .header("path/to/header.h")
    .header_contents("test.h", r#"

struct my_struct {
    int a;
};

enum my_enum {
    I_SAID_YES_ENUM,
    I_SAID_NO_ENUM,
    I_SAID_MV_IT_ENUM,
    I_SAID_MV_IT2_ENUM,
};

#define ERR_FOO 1
#define ERR_BAR 2

"#);

  // Wrap the builder with the helper to handle all additional functionality
  // true to print debug info about the renames to stderr, false to be silent
  let mut helpers = BindingsBuilder::new(builder, true);

  // rename a single item, e.g. a struct, enum, or a typedef
  helpers.rename_item("my_struct", "MyStruct");

  // rename an enum and its values
  rename_enum!(
    helpers,
    "my_enum" => "MyEnum", // rename the enum itself
    remove: "^I_SAID_",    // optionally any number of "remove" regexes
    remove: "_ENUM$",
    case: Pascal,          // optionally set case convert, defaults to "PascalCase"
    "MV_IT" => "Value1",   // rename a specific value after pattern removal
    "MV_IT2" => "Value2",  // more specific value renames
  );

  // Collect matching #define constants into an additional Rust enum.
  // Make sure parameters are given in this order. Skipping is ok.
  define_enum!(
    helpers,
    ErrorCode,             // enum name
    r"^ERR_",              // include matching integer defines
    repr = u32,            // optionally override auto-computed repr type
    min: 0,                // optionally include only values >= min
    max: 999,              // optionally include only values <= max
    exclude: "_PRIVATE$",  // optionally exclude matching defines
    sort: Value,           // optionally sort by Name, Value, or ValueDesc
    derive: [Debug, Copy, Clone, PartialEq, Eq],  // optionally override derives
    remove: "^ERR_",       // optionally any number of "remove" regexes
    case: Pascal,          // optionally set case convert, defaults to "PascalCase"
    "FOOBAR" => "FooBar",  // rename specific values after pattern removal, e.g. to fix some special cases that don't follow the general pattern
  );

  let bindings = helpers.into_string().unwrap();
}

//
// This is the approximate code that would be generated by the above:
//

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct MyStruct {
  pub a: ::std::os::raw::c_int,
}

#[repr(u32)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum MyEnum {
  Yes = 0,
  No = 1,
  Value1 = 2,
  Value2 = 3,
}

pub const ERR_FOO: u32 = 1;
pub const ERR_BAR: u32 = 2;

#[repr(u32)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum ErrorCode {
  Foo = (ERR_FOO as u32),
  Bar = (ERR_BAR as u32),
}

See the list of all case variants supported by the convert_case crate.

Development

  • This project is easier to develop with just, a modern alternative to make. Install it with cargo install just.
  • To get a list of available commands, run just.
  • To run tests, use just test.

License

Licensed under either of

Contribution

Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual-licensed as above, without any additional terms or conditions.

About

Utilities to rename, change case, and fix Rust code generated by bindgen from C headers

Topics

Resources

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages