Skip to content
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

Enums don't match expected behaviour with value mem::zeroed(). #483

Closed
manuel-rhdt opened this issue Feb 6, 2017 · 5 comments
Closed

Enums don't match expected behaviour with value mem::zeroed(). #483

manuel-rhdt opened this issue Feb 6, 2017 · 5 comments

Comments

@manuel-rhdt
Copy link

Hello, while generating bindings for harfbuzz I came upon a very strange bug in my code that wrapped one of the generated types into an Option. Basically this assertion failed:

let value = Some(harfbuzz_struct);
assert!( value.is_some() );

After lots of debugging, I think I found the reason for this obvious misbehaviour. The value I wrapped into the Option was returned from one of harfbuzz's functions. However that value contains an C-enum field that was converted by bindgen (using no flags) into a Rust enum like this:

original C code:
typedef enum {
    FLAG_1 = 0b00000001
} SomeHarfbuzzFlag;
code produced by bindgen
pub const FLAG_1: _bindgen_ty_1 = _bindgen_ty_1::FLAG_1;
#[repr(u32)]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)]
pub enum _bindgen_ty_1 { FLAG_1 = 1, }
pub use self::_bindgen_ty_1 as SomeHarfbuzzFlag;

As you can see the only enum variant that the C code exposes is FLAG_1 with value 1. However the harfbuzz library sometimes returns 0 for values of type SomeHarfbuzzFlag to signify that no flags are given.

This results in very weird behaviour when using the bindings. For example using the code snippets above the following tests fail:

use std::mem;
#[test]
fn test_flag_equality() {
    let flag_zero: SomeHarfbuzzFlag = unsafe { mem::zeroed() };
    assert!( flag_zero != FLAG_1 ); 
}

#[test]
fn test_optional_flag() {
    let flag_zero: SomeHarfbuzzFlag = unsafe { mem::zeroed() };
    let optional = Some(flag_zero);

    assert!( optional.is_some() )
}

I used mem::zeroed() in these examples to mimic the zero value that a C library would return.

@emilio
Copy link
Contributor

emilio commented Feb 6, 2017

Right, this is known (see stuff like #225, etc.) and there are two ways to workaround it.

The first one is using the --bitfield-enum flag, which generates a newtype wrapping an integer and implementing the bitwise or operator, and the other one is the --constified-enum flag, which just generates constants.

@manuel-rhdt
Copy link
Author

Thank you for your response. This workaround works but has another problem however because it is not possible to match name of the enum using the --bitfield-enum regex expression. The enum in my example above has no direct name, because it is typedef'd as SomeHarfbuzzFlag. This means that bindgen will generate an intermediate typename like _bindgen_ty_1 which is not really predictable for the user. Is there any way to still use the --bitfield-enum flag to match against typedef'd enums?

@emilio
Copy link
Contributor

emilio commented Feb 6, 2017

Yes, for unnamed enums, since they're effectively toplevel constants, we match against the individual variants too, you could use `--bitfield-enum "FLAG_.*", and that should work :)

@manuel-rhdt
Copy link
Author

Thank you again, this does indeed work!

@emilio
Copy link
Contributor

emilio commented Feb 6, 2017

Cool, closing this for now then! This is effectively a lack of documentation problem (we are trying to address that, though time is not infinite, so we do our best :P).

Sorry for the trouble and please file more issues if you find any other trouble getting bindgen to work :)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants