rust-lang / rust-lang/rust-bindgen

Another idea for enums representation (and feature request)

Open
#3,057 2 comments 0 reactions 0 assignees View on GitHub

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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. 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

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.