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

Support for derive on unions? #6

Closed
mystor opened this issue Jan 8, 2018 · 10 comments
Closed

Support for derive on unions? #6

mystor opened this issue Jan 8, 2018 · 10 comments

Comments

@mystor
Copy link
Owner

mystor commented Jan 8, 2018

I don't know what the correct behavior for synstructure should be here. In the update for syn 0.12, I intend to simply panic when being passed a union.

We should figure out what to do in that situation.

@dtolnay
Copy link

dtolnay commented Jan 8, 2018

I expect most custom derives will not handle unions and just panic. I included them in DeriveInput because the compiler permits derive on unions. Something like typename_derive will want to support them.

@mystor
Copy link
Owner Author

mystor commented Jan 8, 2018

Yeah, that seems like the most reasonable solution, at least for now.

@joshlf
Copy link

joshlf commented Feb 22, 2019

Now that syn supports Error::to_compiler_error, perhaps the error could be formatted using that instead of panicking? It'd also be cool if unions were supported - I'm working on a custom derive that I suspect will have consumers at some point that use unions.

@mystor
Copy link
Owner Author

mystor commented Nov 11, 2019

synstructure was changed to use Error::to_compiler_error in #28, and handling unions generically probably isn't a good idea. Closing this issue.

@mystor mystor closed this as completed Nov 11, 2019
@joshlf
Copy link

joshlf commented Nov 11, 2019

and handling unions generically probably isn't a good idea

I'm curious what the thinking is here? Do you mean handling unions at all, or does the word "generically" here mean something specific? The reason I ask is that I'd like to be able to support unions in my custom derive at some point. I can use something other than synstructure, of course - I just mean to illustrate that there are real use cases.

@mystor
Copy link
Owner Author

mystor commented Nov 11, 2019

Support for custom derives on unions was added in rust-lang/rust#50383 for consistency with built-in derives, despite most derives not being compatible (rust-lang/rust#50383 (comment)). This is because union field accesses are unsafe, and the correctness of these accesses depends on external logic not visible to the derive implementer.

In effect, a derive which cares about the values of fields cannot support unions, which vastly limits the set of compatible derives. Only specific derives, such as the built-in #[derive(Copy, Clone)], can support unions, and derives which can won't benefit from synstructure, which provides helpers for matching against and accessing fields.

@mystor
Copy link
Owner Author

mystor commented Nov 11, 2019

The reason I ask is that I'd like to be able to support unions in my custom derive at some point. I can use something other than synstructure, of course - I just mean to illustrate that there are real use cases.

If there are specific synstructure features which would be useful for your union derives, I'd be interested to hear about them. It may be worthwhile decoupling them from the Structure type, so that they can be supported there too. Perhaps another type which doesn't provide access to pattern matching or field information could be useful for traits which want to support union as well, which makes it clear that variant values, etc, are not available.

@joshlf
Copy link

joshlf commented Nov 19, 2019

Concretely, I'm interested in deriving the zerocopy traits, which are just unsafe marker traits that don't actually produce any code. For example, a derive of FromBytes for a union would just need to decide whether each individual variant was itself FromBytes. The utility is certainly limited compared to types where field access isn't unsafe, but it's still helpful (for example, to implement variable-length POSIX API structs).

The part of synstructure that we currently make use of is decl_derive!: https://docs.rs/zerocopy-derive/0.1.4/src/zerocopy_derive/lib.rs.html#38.

@mystor
Copy link
Owner Author

mystor commented Nov 19, 2019

I didn't see any uses of Structure other than to extract the .ast() field. This DeriveInput object is easy to get with only syn, so it'd probably be best to just use it directly:

#[proc_macro_derive(FromBytes)]
pub fn derive_from_bytes(ts: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let ast = syn::parse_macro_input!(ts as DeriveInput);
    match &ast.data {
        Data::Struct(strct) => derive_from_bytes_struct(&ast, strct),
        Data::Enum(enm) => derive_from_bytes_enum(&ast, enm),
        Data::Union(uni) => derive_from_bytes_union(&ast, uni),
    }
}

@joshlf
Copy link

joshlf commented Nov 19, 2019

Ah you're probably right. It's been a while since I wrote the code, so I honestly don't remember why I used synstructure. Certainly looks like, whatever the reason, we don't need it anymore.

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

3 participants