Make Debug fancy again and handle #[cfg] properly. #14

Merged
chris-morgan merged 1 commit from master into master 2015-06-29 12:33:51 -05:00
chris-morgan commented 2015-06-25 22:24:15 -05:00 (Migrated from github.com)

Debug was implemented using the nice readable flag names in #7, but the flag names were removed in #9 because it used $Flags which broke trivial #[cfg]-based removal of flags. Changing .contains($Flag) to .contains($BitFlags { bits: $value }) instead (akin to what .all() did) would have fixed that issue, allowing a friendly Debug again, but then I found a further improvement to make, because the #[cfg] behaviour was still off, as a flag’s value was still written out regardless of the #[cfg] attribute, so if it contained stuff that didn’t exist bitflags! would still blow up. This is inconsistent with how such things work in Rust proper, so I’ve fixed it.

The fix is rather convoluted, involving a dummy module, a bunch of dummy constants, a nested function and glob imports, but it works, avoiding referring to $value successfully. This change causes this to work:

bitflags! {
    flags Foo: u32 {
        #[cfg(a)]
        const A = 0b1,
        #[cfg(a)]
        const B = A.bits,  // or anything else that is `#[cfg(a)]`
    }
}

(Formerly all() was still trying to use A.bits when cfg(not(a)) and thus A wasn’t defined.)

This change allows #[cfg] on a flag to work like it should, allowing it to depend on things that don’t exist unless the conditions are met. Sure, that seems a pretty rare case for flags, but it’s real. Beyond the style of example above, my imagined scenario is a -sys crate having declared certain flag values, but only when certain features are enabled, and so when defining the bitflags in another crate (for the -sys crate doesn’t use bitflags) you can only use those values with the appropriate features.

`Debug` was implemented using the nice readable flag names in #7, but the flag names were removed in #9 because it used `$Flags` which broke trivial `#[cfg]`-based removal of flags. Changing `.contains($Flag)` to `.contains($BitFlags { bits: $value })` instead (akin to what `.all()` did) would have fixed that issue, allowing a friendly `Debug` again, but then I found a further improvement to make, because the `#[cfg]` behaviour was still off, as a flag’s value was still written out regardless of the `#[cfg]` attribute, so if _it_ contained stuff that didn’t exist `bitflags!` would still blow up. This is inconsistent with how such things work in Rust proper, so I’ve fixed it. The fix is rather convoluted, involving a dummy module, a bunch of dummy constants, a nested function and glob imports, but it works, avoiding referring to `$value` successfully. This change causes this to work: ``` rust bitflags! { flags Foo: u32 { #[cfg(a)] const A = 0b1, #[cfg(a)] const B = A.bits, // or anything else that is `#[cfg(a)]` } } ``` (Formerly `all()` was still trying to use `A.bits` when `cfg(not(a))` and thus `A` wasn’t defined.) This change allows `#[cfg]` on a flag to work like it should, allowing it to depend on things that don’t exist unless the conditions are met. Sure, that seems a pretty rare case for flags, but it’s real. Beyond the style of example above, my imagined scenario is a -sys crate having declared certain flag values, but only when certain features are enabled, and so when defining the bitflags in another crate (for the -sys crate doesn’t use bitflags) you can only use those values with the appropriate features.
alexcrichton commented 2015-06-29 12:33:58 -05:00 (Migrated from github.com)

Thanks!

Thanks!
Sign in to join this conversation.
No reviewers
No labels
bug
good first issue
No milestone
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
gh-bitflags/bitflags!14
No description provided.