Skip to content

allow renaming rules for C enums, structs, and typedefs #3191

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

nyurik
Copy link
Contributor

@nyurik nyurik commented Apr 10, 2025

Add utilities to rename, change case, and fix Rust code generated from the C headers.

Renamer implements a bindgen callback trait. It handles struct/enum/typedef type renames with a string->string hashmap. Additionally, it can rename the enum variant names by removing regex matches, and change identifier case to PascalCase to be consistent with the Rust canonical style.

This is a port of the https://crates.io/crates/bindgen_helpers into a built-in feature, as it is fairly difficult to maintain a standalone bindgen plugin due to numerous dependency-hell-ish issues I discovered when using it.

// true to enable debug output as warnings
let mut ren = Renamer::new(true);

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

// rename an enum and its values
rename_enum!(
    ren,
    "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
);

let bindings = 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,
};
"#)
    .rustified_enum(ren.get_regex_str())
    .parse_callbacks(Box::new(ren))
    .generate().unwrap();
}

///////////  generated code

#[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,
}

```rust
// true to enable debug output as warnings
let mut ren = Renamer::new(true);

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

// rename an enum and its values
rename_enum!(
    ren,
    "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
);

let bindings = 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,
};
"#)
    .rustified_enum(ren.get_regex_str())
    .parse_callbacks(Box::new(ren))
    .generate().unwrap();
}

///////////  generated code

#[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,
}
```
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant