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.