rust-lang / rust-lang/rust-bindgen
Another idea for enums representation (and feature request)
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 5.3k
- Forks
- 829
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 15
Description
From my experiments with generated enums, I found that the most useful and safe way is to use EnumVariation::ModuleConsts: this method generates pseudo-namespaced values and does not have problems with unexpected values returned from external C functions.
Unfortunately, this method requires a lot of manual boilerplate code to work ergonomically. In particular, it requires manually creating a Rust enum within a safe wrapper, which becomes tedious work for large enums.
Today, I discovered multiple solutions, but they all necessitate sed/awk/regex post-processing for the generated code. One of the most adaptable methods I've implemented is attaching a proc_macro to each module containing constants that creates enums from the const values.
Example:
Generated by bindgen:
mod ResultCodes_enum {
pub type Type =std::os::raw::c_int;
pub const SUCCESS: Type = 0;
pub const FAILURE: Type = 1;
}
After postprocessing and adding custom const_to_enum proc_macro:
#[const_to_enum(ResultCodes)]
mod ResultCodes_enum {
pub type Type = std::os::raw::c_int;
pub const SUCCESS: Type = 0;
pub const FAILURE: Type = 1;
}
The final expanded code looks like this:
use num_enum::{TryFromPrimitive, IntoPrimitive};
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[derive(TryFromPrimitive, IntoPrimitive)]
#[non_exhaustive]
#[repr(i32)
enum ResultCodes {
Success = ResultCodes_enum::SUCCESS,
Failure = ResultCodes_enum::FAILURE,
}
mod ResultCodes_enum {
pub type Type = std::os::raw::c_int;
pub const SUCCESS: Type = 0;
pub const FAILURE: Type = 1;
}
This is a practical solution that still involves some manual effort; all FFI functions return ResultCodes_enum::Type values, and I still need to invoke TryFromPrimitive::try_from for each of these results. Thankfully, I no longer have to manually generate all those Rust enums.
Now, returning to the future request aspect. I really miss having the ability to add an attribute to the generated constant modules, similar to how we can attach custom attributes or derives to generated enums or structs. Currently, I have to rely on tools like sed, awk, or regex for post-processing the generated bindings.
It would also be an option to add such autogenerated enums in the bindgen itself (so that I do not need to write and support a custom proc_macro) and adjust FFI function call wrappers to optionally integrate the num_enum functionality.
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 reviewing EnumVariation::ModuleConsts and how bindgen generates constant modules, then compare the proposed const_to_enum proc_macro approach with custom attributes or derives on generated enums and structs. Define the desired generated Rust enums and any FFI wrapper behavior before considering implementation; done should include a precise supported design and corresponding validation.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- devtools, tooling
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Needs clarification
- Newbie friendliness
- 25/100