rust-lang / rust-lang/rust-bindgen
Add enum option `constified_enum + rustified_enum` with conversions
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 5.3k
- Forks
- 829
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 15
Description
All ways of interop with C enums unfortunately have some downsides. constified-enum, constified-enum-module, newtype-enum, and bitfield-enum can't be matched exhaustively: using the below demo, for example:
match some_foo {
foo_one => println!("1"),
foo_too => println!("2"),
foo_three => println!("3"),
_ => unimplemented!()
}
If a new variant is added to the enum, it gets swallowed with the _. Or a variant may have accidentally be emitted in the first place.
rustified_enum and rustified-non-exhaustive-enum provide more ergonomic solutions and are easier to match, but they don't have good handling for if C provides value not covered by a variant - which is allowed in C. This leads to bugs that can be impossible to track down.
Proposal: allow creating both a constified enum and a Rust enum, and autogenerate three conversion methods between them:
- Safe panicking with
Into - Safe but with an error with
TryInto - Unsafe, assume you never get an unnamed value
Input C/C++ Header
enum foo {
one = 1,
two = 2,
three = 3
};
Bindgen Invocation
bindgen test.h
bindgen test.h --rustified-enum '.*'
Actual Results
pub const foo_one: foo = 1;
pub const foo_two: foo = 2;
pub const foo_three: foo = 3;
pub type foo = ::std::os::raw::c_uint;
#[repr(u32)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum foo {
one = 1,
two = 2,
three = 3,
}
Expected Results
Something like this:
pub const foo_one: foo = 1;
pub const foo_two: foo = 2;
pub const foo_three: foo = 3;
pub type foo_ctype = ::std::os::raw::c_uint;
#[repr(u32)]
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub enum foo {
one = 1,
two = 2,
three = 3,
}
impl From<foo_ctype> for foo {
fn from(value: foo_ctype) -> foo {
match value{
1 => foo::one,
2 => foo::two,
3 => foo::three,
_ => panic!("unrecognized option for `foo` {foo_ctype}"),
}
}
}
struct FooError(foo_ctype);
impl TryFrom<foo_ctype> for foo {
type Error = FooError;
fn try_from(value: foo_ctype) -> Result<foo, FooError> {
match value{
1 => Ok(foo::one),
2 => Ok(foo::two),
3 => Ok(foo::three),
_ => Err(FooError(value)),
}
}
}
impl foo {
const unsafe fn from_ctype_unchecked(value: foo_ctype) -> Self {
std::mem::transmute(value)
}
}
All bindings would use foo_ctype as the value type, but this would give an easy way to turn it into something exhaustive
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start by comparing the existing constified-enum and rustified-enum outputs using the shown bindgen test.h invocations and options. Done means supporting both enum forms together, using a separate C value type, and generating the requested Into, TryInto, and unchecked conversions for unknown values.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c, cpp, rust
- Domain
- compilers, devtools
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 32/100