-
-
Notifications
You must be signed in to change notification settings - Fork 93
add support for deriving NoUninit on enums with fields #292
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
add support for deriving NoUninit on enums with fields #292
Conversation
We check for padding like we do for structs except that we also consider the enum discriminant when calculating the unpadded size.
ecb270e
to
5a6d5a0
Compare
any updates on this? |
good question. I'd totally forgotten about this PR before putting out the derive update yesterday. I'll try to sit down and review it soon. |
Would love to get this in! One thing that might be missing here is the docs for the Line 51 in 028ff3b
|
I believe that comment is based on the fact that, in the general case, if there is an enum variant with a field, the tag byte will always be initialized but the field bytes might not be initialized if it's currently been tagged as some other variant consider:
the byte the u8 sits in is only sometimes initialized. |
That makes sense. This wouldn't be the case if all variants have the same size and there's no padding though, right? |
I think so. Actually I don't know how the tag bytes are considered to work if there's more than one tag byte for alignment. pub enum ColorUsize {
Red(usize),
Green(usize),
} In an enum like this, assuming 64-bit for sake of argument, the tag will be 8 bytes so that the |
As written, this enum is (implicitly) If the enum was |
Alright, then we can absolutely adjust the wording on the trait to allow in additional types of enum that we do get the guarantees for. |
Finally have some bandwidth towards open source again recently, so I'm gonna try to review this in the next few days :) |
As discussed, I believe the full requirements are:
|
The implementation provided in this PR checks all of these requirements by checking that a packed struct of
Hmm, when I originally wrote the code for this PR, I made |
I added some code that computes the integer type of the correct size for the discriminant of |
i think we should error out and require a specific integer type instead of guessing at the probable integer type. In general, the derive should always error out if we're not 100% sure. Any user can "override" our hesitation by just writing the manual impl, if they're that confident we've been too conservative. |
The alternative would be to not assume the discriminant size and derive it by duplicating the type, removing the fields, but keeping any explicit discriminant values, and then looking at the resulting enum's size. That's literally the representation for |
Yeah that would be good. If we're following a spec it's fine. |
Unfortunately, the integer discriminant used for #[repr(C)] doesn't have a name (it's not always core::ffi::c_int), but we can use some compile-time tricks to get the integer type. Use that instead of hard- coding core::ffi::c_int and add support for deriving NoUninit for #[repr(C)] enums.
145284d
to
2b41d97
Compare
I updated the desugaring to transform enums with fields into fieldless enums (as described in the reference) and use that to get the size of the discriminant. |
@fu5ha do you want to do a final check on this before a merge? |
@Lokathor yes, reviewing it now |
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.
A couple of minor comments. In addition to the suggestions/comments in the code, the docs for both the core NoUninit
trait as well as the NoUninit
derive macro need updating. They should enumerate exactly the requirements for when field-ful(?) enums are supported, and link to reference for further info.
Co-authored-by: Gray Olson <gray@grayolson.com>
Thanks for the review @fu5ha ! |
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.
Thanks, pushed a tiny update to the NoUninit
docs, otherwise looks good.
My only hesitation left is the fact we're generating a non-hygenic BlahDiscriminant
type for all #[repr(C)]
enums now, but I don't immediately see a way to prevent that. We already do this with a BlahBits
type for the CheckedBitPattern
derive macro, so it's not un-heardof... @Lokathor what do you think?
The |
Oh! For some reason I thought the LGTM! |
Wait, hm. For the |
This makes the generated code a bit harder to read, but also has the advantage of not unnecessarily adding a type to the global namespace for CheckedBitPattern.
Yup, that works, good idea! |
Awesome :) Thanks for working on this and applying feedback! Think we can merge whenever @Lokathor would like |
Hey @Lokathor would it be possible to publish a new version with this change? |
Ah sorry, I didn't realize it'd been a month already. Let me see what I can do from my phone. |
Should be all good now, 1.10 |
We check for padding like we do for structs except that we also consider the enum discriminant when calculating the unpadded size.