Skip to content

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

Merged
merged 8 commits into from
Jan 20, 2023
Merged

Implement cli option for custom derive #2328

merged 8 commits into from
Jan 20, 2023

Conversation

hcldan
Copy link
Contributor

@hcldan hcldan commented Nov 1, 2022

closes #2170

@hcldan
Copy link
Contributor Author

hcldan commented Nov 1, 2022

not sure why rustfmt runner failed.

.value_name("trait")
.multiple_occurrences(true)
.number_of_values(1),
Arg::new("with-derive-custom-struct")
Copy link
Contributor

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?

Copy link
Contributor Author

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.

@pvdrz
Copy link
Contributor

pvdrz commented Nov 2, 2022

@hcldan could you add some tests?

@bors-servo
Copy link

☔ The latest upstream changes (presumably a673a6b) made this pull request unmergeable. Please resolve the merge conflicts.

@pvdrz pvdrz mentioned this pull request Nov 18, 2022
@pvdrz
Copy link
Contributor

pvdrz commented Nov 21, 2022

Now that #2355 and #2330 have been merged it should be possible to:

  • Use --with-derive-custom and --with-derive-custom-struct at the same time without issue.
  • Add a field to DepInfo for handling structures instead of adding another method to ParseCallbacks.

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.

@hcldan
Copy link
Contributor Author

hcldan commented Nov 23, 2022

I can look into doing this.
Sorry for the delay in responding, I was at a customer conference and then I got sick :)

@hcldan
Copy link
Contributor Author

hcldan commented Dec 1, 2022

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.

@hcldan hcldan requested a review from pvdrz December 2, 2022 13:36
Copy link
Contributor

@pvdrz pvdrz left a 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 :)

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
Copy link
Contributor

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 unions are emitted as rust structs and CompKind doesn't include enums` 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.

Copy link
Contributor Author

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?

Copy link
Contributor

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:

let mut tokens = if is_union && struct_layout.is_rust_union() {
quote! {
#( #attributes )*
pub union #canonical_ident
}
} else {
quote! {
#( #attributes )*
pub struct #canonical_ident
}
};

.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: \
Copy link
Contributor

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.

Copy link
Contributor Author

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

#[non_exhaustive]
pub struct DeriveInfo<'a> {
/// The name of the type.
pub name: &'a str,
/// The kind of the type
pub kind: Option<CompKind>,
Copy link
Contributor

@pvdrz pvdrz Dec 5, 2022

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
    }

Copy link
Contributor Author

@hcldan hcldan Dec 5, 2022

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.

Copy link
Contributor

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 enums instead of being for "every" kind of type definition.

@@ -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()),
Copy link
Contributor

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()

cb.add_derives(&crate::callbacks::DeriveInfo { name: &name })
cb.add_derives(&crate::callbacks::DeriveInfo {
name: &name,
kind: None,
Copy link
Contributor

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.

#[non_exhaustive]
pub struct DeriveInfo<'a> {
/// The name of the type.
pub name: &'a str,
/// The kind of the type
pub kind: Option<CompKind>,
Copy link
Contributor

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 enums instead of being for "every" kind of type definition.

@hcldan
Copy link
Contributor Author

hcldan commented Dec 8, 2022

@pvdrz Thank you for the feedback, I think these are good suggestions, but I don't have the time to address them :(
Work is piling up

@pvdrz
Copy link
Contributor

pvdrz commented Dec 8, 2022

I can do the extra changes if that's OK with you. This is really close to be done :)

@hcldan
Copy link
Contributor Author

hcldan commented Dec 12, 2022

that would be great!

@hcldan
Copy link
Contributor Author

hcldan commented Jan 3, 2023

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.

@pvdrz
Copy link
Contributor

pvdrz commented Jan 5, 2023

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.

@bors-servo
Copy link

☔ The latest upstream changes (presumably ed2d06e) made this pull request unmergeable. Please resolve the merge conflicts.

@pvdrz pvdrz changed the base branch from master to main January 20, 2023 19:37
@pvdrz pvdrz merged commit bca47cd into rust-lang:main Jan 20, 2023
@hcldan
Copy link
Contributor Author

hcldan commented Jan 26, 2023

@pvdrz any chance for a new release?

@pvdrz
Copy link
Contributor

pvdrz commented Jan 26, 2023

our release policy is whenever someone asks 🤣

I'll get a new release ready soon.

@hcldan
Copy link
Contributor Author

hcldan commented Jan 27, 2023

@pvdrz Cheers!

@hcldan
Copy link
Contributor Author

hcldan commented Feb 6, 2023

@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.

@pvdrz
Copy link
Contributor

pvdrz commented Feb 6, 2023

👋 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

@pvdrz
Copy link
Contributor

pvdrz commented Feb 7, 2023

@hcldan the new version has just been published

@hcldan
Copy link
Contributor Author

hcldan commented Feb 7, 2023

@pvdrz ❤️ Thank you!

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

Successfully merging this pull request may close these issues.

CLI support for custom derives
3 participants