Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
nikkon-dev opened this issue Dec 17, 2024 · 2 comments
Open

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

nikkon-dev opened this issue Dec 17, 2024 · 2 comments

Comments

@nikkon-dev
Copy link
Contributor

nikkon-dev commented Dec 17, 2024

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.

@ojeda
Copy link
Contributor

ojeda commented Dec 17, 2024

It would also be an option to add such autogenerated enums in the bindgen itself

Please see #2646 and #3051.

@nikkon-dev
Copy link
Contributor Author

It would also be an option to add such autogenerated enums in the bindgen itself

Please see #2646 and #3051.
Thank you!

The #3051 is the closest to the results I'm getting (except that I'd prefer to use the named costs instead of duplicated integer values in both places).

That still leaves the original feature request - be able to add attributes to generated const modules.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants