Skip to content

Another idea for enums representation (and feature request) #3057

Open
@nikkon-dev

Description

@nikkon-dev

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions