-
Notifications
You must be signed in to change notification settings - Fork 741
Implement cli option for custom derive #2328
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
Conversation
not sure why rustfmt runner failed. |
bindgen-cli/options.rs
Outdated
.value_name("trait") | ||
.multiple_occurrences(true) | ||
.number_of_values(1), | ||
Arg::new("with-derive-custom-struct") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
maybe I'm missing something but why aren't there equivalents for enum
and union
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Because I didn't need those, and they caused huge issues with the Derive I was trying to use.
The support is there in the base project, I was implementing this because I need this on the cli.
@hcldan could you add some tests? |
☔ The latest upstream changes (presumably a673a6b) made this pull request unmergeable. Please resolve the merge conflicts. |
Now that #2355 and #2330 have been merged it should be possible to:
It seems that taking a regex argument is something important here but that can be done in a different PR. @hcldan let me know what do you think. |
I can look into doing this. |
Tried to follow what was going on but I needed some internals. LMK if this is looking like it's the right direction and I'll add some tests. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks great! I suggested changes about some small details but this is looking great :)
bindgen-cli/options.rs
Outdated
fn add_derives(&self, info: &bindgen::callbacks::DeriveInfo<'_>) -> Vec<String> { | ||
match self.kind.to_lowercase().as_str() { | ||
"struct" => match info.kind { | ||
Some(bindgen::ir::comp::CompKind::Struct) => {}, // continue |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm this brings up again a discussion we had with @emilio before. Should this <kind>
be the kind of c
types or rust
types? For example some c
union
s are emitted as rust
struct
s and CompKind
doesn't include enum
s` as those aren't compound types per-se.
I'm more inclined to this based on the rust
kinds instead as we're deriving rust
traits on them but I'm open to hear other arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's a good question... I think I agree with you... which kind of kind (😄 ) am I using here?
I was not expecting to not find enums in the enum for CompKind (this is starting to get meta...)
So I gave up on the branch of code that handles everything but structs and unions.
If this is referencing C types, how do I get the rust types to check?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deciding whether a comptype becomes a rust struct or union happens here:
rust-bindgen/bindgen/codegen/mod.rs
Lines 2122 to 2132 in 9c2167c
let mut tokens = if is_union && struct_layout.is_rust_union() { | |
quote! { | |
#( #attributes )* | |
pub union #canonical_ident | |
} | |
} else { | |
quote! { | |
#( #attributes )* | |
pub struct #canonical_ident | |
} | |
}; |
bindgen-cli/options.rs
Outdated
.long("with-derive-custom") | ||
.help( | ||
"Derive custom traits on any kind of type. \ | ||
The derive value must be of the shape <regex>=<kind>=<derive> where <kind> can be one of: \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd be more inclined to keep this as you had it before --with-derive-custom-struct
iirc and pass <regex>=<derive>
as arguments.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hmm... ok but I might wait for resolution on the previous comment first
bindgen/callbacks.rs
Outdated
#[non_exhaustive] | ||
pub struct DeriveInfo<'a> { | ||
/// The name of the type. | ||
pub name: &'a str, | ||
/// The kind of the type | ||
pub kind: Option<CompKind>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this shoudn't be wrapped in an Option
but the user should be able to ignore the kind
if they want to from the callback implementation directly:
fn add_derives(&self, info: &bindgen::callbacks::DeriveInfo<'_>) -> Vec<String> {
let mut derives = vec![];
match &info.kind {
CompKind::Struct => /* add derives exclusive for `struct`s */,
CompKind::Union => /* add derives exclusive for `union`s */,
}
/* add derives for any kind of type */
derives
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Well I wasn't regexing on CompKind values, and there's no Any
member of that enum, so I figured that if you wanted them all, we could use None, and if you wanted none then you shouldn't be using the option 😄
This was to allow for the other branch where I don't filter by CompKind because it is not available. I did not want to stop people who wanted to derive things on other rust types that support it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the None
confusing because if someone does something like:
fn add_derives(&self, info: &bindgen::callbacks::DeriveInfo<'_>) -> Vec<String> {
if info.kind.is_none() {
vec!["serde::Serialize"]
} else {
vec![]
}
}
Then Serialize
would only be derived for rust enum
s instead of being for "every" kind of type definition.
bindgen/codegen/mod.rs
Outdated
@@ -2105,6 +2105,7 @@ impl CodeGenerator for CompInfo { | |||
let custom_derives = ctx.options().all_callbacks(|cb| { | |||
cb.add_derives(&crate::callbacks::DeriveInfo { | |||
name: &canonical_name, | |||
kind: Some(self.kind()), |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Continuation of #2328 (comment)
So what I'd do is defining a new enum
called TypeKind
or ItemKind
that can be used instead of CompKind
inside of DeriveInfo
:
enum WhateverKind {
Struct,
Enum,
Union,
}
and then use the condition is_union && struct_layout.is_rust_union()
to decide if the current type will be represented as a rust union
or as a struct
and use WhateverKind::Union
or WhateverKind::Struct
accordingly instead of self.kind()
bindgen/codegen/mod.rs
Outdated
cb.add_derives(&crate::callbacks::DeriveInfo { name: &name }) | ||
cb.add_derives(&crate::callbacks::DeriveInfo { | ||
name: &name, | ||
kind: None, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Continuation of https://github.com/rust-lang/rust-bindgen/pull/2328/files#r1043753788
And here I'd use kind: WhateverKind::Enum
as this is the CodeGenerator
implementation for Enum
.
In that way you don't need the Option
wrapper either.
bindgen/callbacks.rs
Outdated
#[non_exhaustive] | ||
pub struct DeriveInfo<'a> { | ||
/// The name of the type. | ||
pub name: &'a str, | ||
/// The kind of the type | ||
pub kind: Option<CompKind>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I find the None
confusing because if someone does something like:
fn add_derives(&self, info: &bindgen::callbacks::DeriveInfo<'_>) -> Vec<String> {
if info.kind.is_none() {
vec!["serde::Serialize"]
} else {
vec![]
}
}
Then Serialize
would only be derived for rust enum
s instead of being for "every" kind of type definition.
@pvdrz Thank you for the feedback, I think these are good suggestions, but I don't have the time to address them :( |
I can do the extra changes if that's OK with you. This is really close to be done :) |
that would be great! |
looks like it doesn't want to derive the traits on unions. I ran into this at work, few (if any) derives have worked on any unions I've seen. |
Yeah that part is a bit tricky but the actual main issue is that we cannot recover the CLI flags because we're using a callback. We're still discussing what's the best way forward. |
☔ The latest upstream changes (presumably ed2d06e) made this pull request unmergeable. Please resolve the merge conflicts. |
@pvdrz any chance for a new release? |
our release policy is whenever someone asks 🤣 I'll get a new release ready soon. |
@pvdrz Cheers! |
@pvdrz friendly reminder if it's not too much trouble, I could really use a new release to move to the functionality in this PR. |
👋 hey I haven't forgot. I'm trying to get a new feature merged alongside this one before releasing a new version. If this feature does not land on friday I'll do a release anyway |
@hcldan the new version has just been published |
@pvdrz ❤️ Thank you! |
closes #2170