Updating some old bindings, something seems to have changed


#1

Trying to create Rust bindings for speech-dispatcher. Yesterday I published the speech-dispatcher-sys crate based on the newest bindgen. I’d been using an older bindgen a few months ago, and in my higher-level speech-dispatcher crate I had code like:

pub enum CapitalLetters {
    None = SPDCapitalLetters_SPD_CAP_NONE as isize,
    Spell = SPDCapitalLetters_SPD_CAP_SPELL as isize,
    Icon = SPDCapitalLetters_SPD_CAP_ICON as isize,
}

Then functions like:

    pub fn set_capital_letters_uid(&self, capital_letters: CapitalLetters, target_uid: u32) -> bool {
        let v = unsafe { spd_set_capital_letters_uid(self.connection, capital_letters as u32, target_uid) };
        i32_to_bool(v)
    }
...

fn i32_to_bool(v: i32) -> bool {
    if v == 1 { true } else { false }
}

But now I get:

    |                                                                        22 caret characters expected enum `speech_dispatcher_sys::SPDCapitalLetters`, found u32

So I used to be able to cast the enum value to u32, but it now looks like the bindgen functions in the sys crate take the enum directly.

I guess my initial question is, how do I change this code such that the sys crate gets what it expects? Do I have to implement Into or add match statements on each of dozens of functions or enums? But, looking deeper, another possibility would be if I could re-export these awful sys enum values as something more rusty. How should I fix this?


#2

You need --rustified-enum <regex> to opt-in to enum.

That’s because Rust will corrupt memory and crash hard if you cast u32 to an enum with a value that isn’t strictly part of the enum. C sometimes uses enums for values that are OR-ed together, and Rust can’t allow that.

For example:

enum Foo {
A = 1,
B = 2,
}

extern "C" fn take_enum(foo: Foo);

calling take_enum(3) is undefined behavior, and the risk is not theoretical, but it actually causes match to misbehave badly.