Skip to content

Commit 1464db3

Browse files
committed
Add callback to allow renaming result error enum
1 parent 9930921 commit 1464db3

File tree

5 files changed

+113
-3
lines changed

5 files changed

+113
-3
lines changed

bindgen-tests/tests/expectations/tests/parsecb-result-error-enum-name.rs

+22
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
// bindgen-flags: --result-error-enum MyResult --rust-target 1.79
2+
// bindgen-parse-callbacks: result-error-enum-rename
3+
4+
enum MyResult {
5+
MyResultOk = 0,
6+
MyResultInvalid,
7+
MyResultAnotherError,
8+
};
9+
10+
typedef enum MyResult AnotherResult;
11+
12+
enum MyResult some_function(void);
13+
14+
AnotherResult another_function(void);

bindgen-tests/tests/parse_callbacks/mod.rs

+15
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,20 @@ impl ParseCallbacks for EnumVariantRename {
7272
}
7373
}
7474

75+
#[derive(Debug)]
76+
struct ResultErrorEnumRename;
77+
78+
impl ParseCallbacks for ResultErrorEnumRename {
79+
fn result_error_enum_name(
80+
&self,
81+
original_enum_name: &str,
82+
) -> Option<String> {
83+
original_enum_name
84+
.strip_suffix("Result")
85+
.map(|base| format!("{base}Error"))
86+
}
87+
}
88+
7589
#[derive(Debug)]
7690
struct BlocklistedTypeImplementsTrait;
7791

@@ -149,6 +163,7 @@ impl ParseCallbacks for WrapAsVariadicFn {
149163
pub fn lookup(cb: &str) -> Box<dyn ParseCallbacks> {
150164
match cb {
151165
"enum-variant-rename" => Box::new(EnumVariantRename),
166+
"result-error-enum-rename" => Box::new(ResultErrorEnumRename),
152167
"blocklisted-type-implements-trait" => {
153168
Box::new(BlocklistedTypeImplementsTrait)
154169
}

bindgen/callbacks.rs

+54
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,60 @@ pub trait ParseCallbacks: fmt::Debug {
7979
None
8080
}
8181

82+
/// Allows to rename the error enum name for a result-error-enum
83+
///
84+
/// When the original C-enum is translated to a `Result<(), NonZero<ErrorEnum>>` representation,
85+
/// the original enum name is used as a type alias for the result.
86+
/// The error enum hence must have a different name. By default, we simply append an `Error` to
87+
/// the typename, but this callback allows overriding the name for the error enum.
88+
/// Please note that the new enum name returned by this callback must be distinct from the
89+
/// original enum name.
90+
///
91+
/// ### Example
92+
///
93+
/// Given a header file like this:
94+
/// ```c
95+
/// enum MyResult {
96+
/// MyResultOk = 0,
97+
/// MyResultInvalid,
98+
/// MyResultAnotherError,
99+
/// };
100+
/// ```
101+
/// A user could the implement the following callback:
102+
/// ```rust
103+
/// # use bindgen::callbacks::ParseCallbacks;
104+
/// #[derive(Debug)]
105+
/// struct ResultErrorEnumRename;
106+
///
107+
/// impl ParseCallbacks for ResultErrorEnumRename {
108+
/// fn result_error_enum_name(
109+
/// &self,
110+
/// original_enum_name: &str,
111+
/// ) -> Option<String> {
112+
/// original_enum_name
113+
/// .strip_suffix("Result")
114+
/// .map(|base| format!("{base}Error"))
115+
/// }
116+
/// }
117+
/// ```
118+
///
119+
/// The above callback would result in the following rust binding:
120+
///
121+
/// ```no_run
122+
/// # // Note: doctests break when running with MSRV.
123+
/// pub type MyResult = Result<(), MyError>;
124+
/// #[repr(transparent)]
125+
/// #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
126+
/// pub struct MyError(pub core::num::NonZero<::std::os::raw::c_uint>);
127+
/// // <Definition of MyError variants>
128+
/// ```
129+
fn result_error_enum_name(
130+
&self,
131+
_original_enum_name: &str,
132+
) -> Option<String> {
133+
None
134+
}
135+
82136
/// Allows to rename an enum variant, replacing `_original_variant_name`.
83137
fn enum_variant_name(
84138
&self,

bindgen/codegen/mod.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -3316,6 +3316,7 @@ impl<'a> EnumBuilder<'a> {
33163316
/// the representation, and which variation it should be generated as.
33173317
fn new(
33183318
name: &'a str,
3319+
ctx: &BindgenContext,
33193320
mut attrs: Vec<proc_macro2::TokenStream>,
33203321
repr: syn::Type,
33213322
enum_variation: EnumVariation,
@@ -3329,8 +3330,12 @@ impl<'a> EnumBuilder<'a> {
33293330
is_global,
33303331
is_result_type: true,
33313332
} => {
3332-
// Todo: This identifier perhaps could be determined by a ParseCallback.
3333-
let error_ident = format_ident!("{}Error", ident);
3333+
let error_enum_name = ctx
3334+
.options()
3335+
.last_callback(|c| c.result_error_enum_name(&name))
3336+
.unwrap_or(format!("{name}Error"));
3337+
let error_ident =
3338+
Ident::new(&error_enum_name, Span::call_site());
33343339
EnumBuilder::NewType {
33353340
canonical_name: name,
33363341
tokens: quote! {
@@ -3837,7 +3842,7 @@ impl CodeGenerator for Enum {
38373842
let has_typedef = ctx.is_enum_typedef_combo(item.id());
38383843

38393844
let mut builder =
3840-
EnumBuilder::new(&name, attrs, repr, variation, has_typedef);
3845+
EnumBuilder::new(&name, ctx, attrs, repr, variation, has_typedef);
38413846

38423847
// A map where we keep a value -> variant relation.
38433848
let mut seen_values = HashMap::<_, Ident>::default();

0 commit comments

Comments
 (0)