-
Notifications
You must be signed in to change notification settings - Fork 12.8k
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 a bitflags! macro #13072
Add a bitflags! macro #13072
Conversation
//! # Example | ||
//! | ||
//! ~~~rust | ||
//! bitset!(Flags: u32 { |
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.
Does this example actually pass tests?
Don't you need to import the macro with a #[phase(syntax)] extern crate collections;
?
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.
Weird, all the tests passed. Doesn't seem like it ran:
run doc-crate-collections [x86_64-apple-darwin]
running 2 tests
test hashmap::HashMap_0 ... ok
test lru_cache_0 ... ok
Maybe I should remove rust
in ~~~rust
?
Come to think of it, how would I do this test? I thought you couldn't do #[phase(syntax)] extern crate collections;
from within a doc test? Also, the bitset!
macro needs to be invoked at the item level.
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.
Oh, yeah, maybe it's the rust
or maybe its the ~~~
(most tests use
```
)
But if you put a fn main() {}
in the test somewhere, rustdoc will no longer automatically insert the wrapping function main, so I think
#[feature(phase)];
#[phase(syntax)] extern crate collections;
/* bitset!() declaration */
fn main() {
let e1 = FlagA | FlagC;
// etc.
}
might work.
Rebased. |
I added some documentation showing how bitflags can be extended with trait and type implementations. |
//! - `insert`: inserts the specified flags in-place | ||
//! - `remove`: removes the specified flags in-place | ||
|
||
#[macro_escape]; |
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 isn't really needed since nothing else in libcollections uses bitflags!
.
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.
Oh, so that isn't needed for exporting macros?
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.
#[macro_escape]
lets the definition escape to the next scope level (the crate root in this case). It's unrelated to #[macro_export]
.
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.
Ahh, I knew about the escaping bit, but yeah, wasn't sure about the exporting.
This seems pretty interesting, but is there a reason that the existing |
#[repr(u32)]
enum InitFlags {
InitTimer = 0x00000001,
InitAudio = 0x00000010,
InitVideo = 0x00000020,
InitJoystick = 0x00000200,
InitHaptic = 0x00001000,
InitGamecontroller = 0x00002000,
InitEvents = 0x00004000,
InitNoparachute = 0x00100000,
InitEverything = InitTimer as u32
| InitAudio as u32
| InitVideo as u32
| InitEvents as u32
| InitJoystick as u32
| InitHaptic as u32
| InitGamecontroller as u32,
}
impl CLike for InitFlags {
fn to_uint(&self) -> uint {
*self as uint
}
fn from_uint(v: uint) -> InitFlags {
unsafe { cast::transmute(v as u32) }
}
}
// ...
let mut flags = EnumSet::empty();
flags.add(sdl2::InitVideo);
flags.add(sdl2::InitEvents);
sdl2::init(flags) bitflags!(InitFlags: Uint32 {
InitTimer = 0x00000001,
InitAudio = 0x00000010,
InitVideo = 0x00000020,
InitJoystick = 0x00000200,
InitHaptic = 0x00001000,
InitGamecontroller = 0x00002000,
InitEvents = 0x00004000,
InitNoparachute = 0x00100000,
InitEverything = InitTimer.bits
| InitAudio.bits
| InitVideo.bits
| InitEvents.bits
| InitJoystick.bits
| InitHaptic.bits
| InitGamecontroller.bits
})
// ...
sdl2::init(sdl2::InitVideo | sdl2::InitEvents) |
I also think that the iterator might be broken, for example: let mut flags = collections::EnumSet::empty();
flags.add(InitJoystick);
flags.add(InitVideo);
flags.add(InitHaptic);
for flag in flags.iter() {
println!("{}", flag);
} Prints:
Of course that does not mean that the implementation could not be fixed. |
Some of your concerns can be addressed by updating the I'm worried about having two bit sets, and I'd like to reconcile the two of them before landing. |
Removing the iterator, which seems to be broken, would remove the need for |
We could reccomend that library implementors implement specific operator overloads for convenience. For example you could have |
I think this is a great idea. I have actually came up with a eerily similar implementation for my own libraries: definition/usage. My primary motivation was the bitwise operators interface, but it seems to me if I actually tried using EnumSet I'd have run into the remaining issues bjz mentioned. |
EnumSet uses a phantom type to bind the usage, but since the generic constraint is decoupled from the type declaration, it becomes more confusing. From a user-friendly perspective I think bitflags is better. It took me 3 seconds to understand how bitflags is used, but I am still pondering whether EnumSet doesn't have any caveats I am not aware about. |
Was that from looking at the code, or my documentation? Macros can be pretty hard to document. |
EnumSet lacks code example, which could clarify the usage quite a bit. I learned the usage of bitflags by looking at the example and the documentation gives better in-depth explanation. I like that you can specify the type and not rely on uint which EnumSet uses. I think EnumSet is useful in cases where one can not alter the enum declaration. It can also be used to generate uint (with CLike) as a meta type for enum variants, which bitflags does not support. It seems to me that the use cases does not completely overlap. Maybe we could have both? |
I would just like to add a severe limitation to the |
I have basically a similar implementation as well (just implemented Sub and is_zero after I saw your code.) I think you should make negation possible. Recursive macros can match the head/tail of the list of flags and optionally default to the value of the previous flag shifted by one. |
Now that is cool! If only we could fix the documentation issue... |
@bjz: this PR was discussed in the weekly meeting today, and consensus was that we should merge it, but as part of We can improve the documentation aspect later on, once sufficient macro support is available. Can you please update to move to |
@aturon sure thing! |
The `bitflags!` macro generates a `struct` that holds a set of C-style bitmask flags. It is useful for creating typesafe wrappers for C APIs. For example: ~~~rust #[feature(phase)]; #[phase(syntax)] extern crate collections; bitflags!(Flags: u32 { FlagA = 0x00000001, FlagB = 0x00000010, FlagC = 0x00000100, FlagABC = FlagA.bits | FlagB.bits | FlagC.bits }) fn main() { let e1 = FlagA | FlagC; let e2 = FlagB | FlagC; assert!((e1 | e2) == FlagABC); // union assert!((e1 & e2) == FlagC); // intersection assert!((e1 - e2) == FlagA); // set difference } ~~~
Rebased. |
//! - `intersects`: `true` if there are flags common to both `self` and `other` | ||
//! - `contains`: `true` all of the flags in `other` are contained within `self` | ||
//! - `insert`: inserts the specified flags in-place | ||
//! - `remove`: removes the specified flags in-place |
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.
Now that we can put documentation on macros themselves, I wonder if this would be best suited on the macro itself.
I suppose if you search for bitflags
you'll probably hit the module before the macro, though.
r=me with the updated examples (removing the |
This will allow us to provide type-safe APIs in libstd that are C-compatible.
The `bitflags!` macro generates a `struct` that holds a set of C-style bitmask flags. It is useful for creating typesafe wrappers for C APIs. For example: ~~~rust #[feature(phase)]; #[phase(syntax)] extern crate collections; bitflags!(Flags: u32 { FlagA = 0x00000001, FlagB = 0x00000010, FlagC = 0x00000100, FlagABC = FlagA.bits | FlagB.bits | FlagC.bits }) fn main() { let e1 = FlagA | FlagC; let e2 = FlagB | FlagC; assert!((e1 | e2) == FlagABC); // union assert!((e1 & e2) == FlagC); // intersection assert!((e1 - e2) == FlagA); // set difference } ~~~
Is there any chance this will support |
@jcmoyer: I'm not sure that |
@thestinger: I'd expect As for |
My point was that since subtraction is performing a set difference, arithmetic/bitwise operators without a set equivalent don't make much sense. |
@thestinger: Makes sense. Thanks for clarifying. |
I feel that this is a very vital, missing piece of functionality. This adds on to #13072. Only bits used in the definition of the bitflag are considered for the universe set. This is a bit safer than simply inverting all of the bits in the wrapped value. ```rust bitflags!(flags Flags: u32 { FlagA = 0x00000001, FlagB = 0x00000010, FlagC = 0x00000100, FlagABC = FlagA.bits | FlagB.bits | FlagC.bits }) ... // `Not` implements set complement assert!(!(FlagB | FlagC) == FlagA); // `all` and `is_all` are the inverses of `empty` and `is_empty` assert!(Flags::all() - FlagA == !FlagA); assert!(FlagABC.is_all()); ```
…jonas-schievink feat: Add a "Unmerge match arm" assist to split or-patterns inside match expressions Fixes rust-lang#13072. The way I implemented it it leaves the `OrPat` in place even if there is only one pattern now but I don't think something will break because of that, and when more code will be typed we'll parse it again anyway. Removing it (but keeping the child pattern) is hard, I don't know how to do that.
Misc refactorings part 5 `toplevel_ref_arg` gets a small fix so it can be allowed on function arguments. Otherwise just some rearrangements. changelog: none
The
bitflags!
macro generates astruct
that holds a set of C-style bitmask flags. It is useful for creating typesafe wrappers for C APIs.For example: