rust-bindgen icon indicating copy to clipboard operation
rust-bindgen copied to clipboard

The enum_name argument for enum_variant_name fn of ParseCallbacks trait includes the enum keyword along with the name

Open coderedart opened this issue 10 months ago • 4 comments

If I run the following code with bindgen version 0.71.1 (latest as of this moment):

fn main() {
    let code = r"
        typedef enum MyEnum {
            MyEnumVariantA,
            MyEnumVariantB,
        } MyEnum;
    ";
    #[derive(Debug)]
    struct ParseCb;
    impl bindgen::callbacks::ParseCallbacks for ParseCb {
        fn enum_variant_name(
            &self,
            enum_name: Option<&str>,
            _original_variant_name: &str,
            _variant_value: bindgen::callbacks::EnumVariantValue,
        ) -> Option<String> {
            dbg!(enum_name);
            None
        }
    }
    bindgen::builder()
        .parse_callbacks(Box::new(ParseCb))
        .header_contents("temp.h", code)
        .generate()
        .unwrap();
}

I get this output:

[src/main.rs:17:13] enum_name = Some(
    "enum MyEnum",
)
[src/main.rs:17:13] enum_name = Some(
    "enum MyEnum",
)

We should only get the MyEnum part. If this is not a bug, then, it should at least be documented in the function docs.

Temporary workaround: just do enum_name.strip_prefix("enum ") (note the space after the enum keyword).

coderedart avatar Feb 05 '25 10:02 coderedart

Yeah, it would be best to document it and add a test (I couldn't find one from a quick look).

However, to clarify, what should be the expected output given the following?

typedef enum E { A } T;

ojeda avatar Feb 05 '25 11:02 ojeda

By default, E seems to be the obvious name to use, because T is just an alias. For example, if I used

        typedef enum MyEnum {
            MyEnumVariantA,
            MyEnumVariantB,
        } Foo;

I get this (using rust enum style):

#[repr(u32)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum MyEnum { // E stays as name
    MyEnumVariantA = 0,
    MyEnumVariantB = 1,
}
pub use self::MyEnum as Foo; // T stays as alias

If there's no E, then T can be used as convenience?

In the context of enum_variant_name callback, having another argument called enum_alias is enough for people who want to customize the variant names based on alias.

coderedart avatar Feb 05 '25 11:02 coderedart

I agree E should be the one picked -- I was trying to disambiguate/clarify the example in OP.

If there's no E, then T can be used as convenience?

That creates ambiguity, so I think that should be avoided and instead provided separately.

ojeda avatar Feb 05 '25 11:02 ojeda

Note that these two examples generate different callbacks. I think both should be generating identical callbacks - as that's what actually gets generated as Rust code, regardless of how it was declared (first has "enum", and second does not)

enum my_enum1 { foo1 };
// callback
enum_variant_name(
    enum_name=Some("enum my_enum1"),
    value="foo1",
    variant_value=EnumVariantValue::Unsigned(0)
)
typedef enum { foo2 } my_enum2;
// callback
enum_variant_name(
    enum_name=Some("my_enum2"),
    value="foo2",
    variant_value=EnumVariantValue::Unsigned(0)
)

Update

I tried two more test cases:

typedef enum my_enum3 { foo3 } my_enum3;
typedef enum my_enum4a { foo4 } my_enum4b;

and got results similar to the first case (with "enum"):

enum_name=Some("enum my_enum3") value=foo3 variant_value=Unsigned(0)
enum_name=Some("enum my_enum4a") value=foo4 variant_value=Unsigned(0)

nyurik avatar May 01 '25 06:05 nyurik