Skip to content

Commit a3f9f37

Browse files
committed
auto merge of #13072 : bjz/rust/bitset, r=alexcrichton
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 } ~~~
2 parents 7e9f3ea + 63ee7bb commit a3f9f37

File tree

2 files changed

+260
-0
lines changed

2 files changed

+260
-0
lines changed

src/libstd/bitflags.rs

+257
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,257 @@
1+
// Copyright 2014 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
//! The `bitflags!` macro generates a `struct` that holds a set of C-style
12+
//! bitmask flags. It is useful for creating typesafe wrappers for C APIs.
13+
//!
14+
//! The flags should only be defined for integer types, otherwise unexpected
15+
//! type errors may occur at compile time.
16+
//!
17+
//! # Example
18+
//!
19+
//! ~~~rust
20+
//! bitflags!(Flags: u32 {
21+
//! FlagA = 0x00000001,
22+
//! FlagB = 0x00000010,
23+
//! FlagC = 0x00000100,
24+
//! FlagABC = FlagA.bits
25+
//! | FlagB.bits
26+
//! | FlagC.bits
27+
//! })
28+
//!
29+
//! fn main() {
30+
//! let e1 = FlagA | FlagC;
31+
//! let e2 = FlagB | FlagC;
32+
//! assert!((e1 | e2) == FlagABC); // union
33+
//! assert!((e1 & e2) == FlagC); // intersection
34+
//! assert!((e1 - e2) == FlagA); // set difference
35+
//! }
36+
//! ~~~
37+
//!
38+
//! The generated `struct`s can also be extended with type and trait implementations:
39+
//!
40+
//! ~~~rust
41+
//! use std::fmt;
42+
//!
43+
//! bitflags!(Flags: u32 {
44+
//! FlagA = 0x00000001,
45+
//! FlagB = 0x00000010
46+
//! })
47+
//!
48+
//! impl Flags {
49+
//! pub fn clear(&mut self) {
50+
//! self.bits = 0; // The `bits` field can be accessed from within the
51+
//! // same module where the `bitflags!` macro was invoked.
52+
//! }
53+
//! }
54+
//!
55+
//! impl fmt::Show for Flags {
56+
//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
57+
//! write!(f.buf, "hi!")
58+
//! }
59+
//! }
60+
//!
61+
//! fn main() {
62+
//! let mut flags = FlagA | FlagB;
63+
//! flags.clear();
64+
//! assert!(flags.is_empty());
65+
//! assert_eq!(format!("{}", flags), ~"hi!");
66+
//! }
67+
//! ~~~
68+
//!
69+
//! # Derived traits
70+
//!
71+
//! The `Eq`, `TotalEq`, and `Clone` traits are automatically derived for the
72+
//! `struct` using the `deriving` attribute.
73+
//!
74+
//! # Operators
75+
//!
76+
//! The following operator traits are implemented for the generated `struct`:
77+
//!
78+
//! - `BitOr`: union
79+
//! - `BitAnd`: intersection
80+
//! - `Sub`: set difference
81+
//!
82+
//! # Methods
83+
//!
84+
//! The following methods are defined for the generated `struct`:
85+
//!
86+
//! - `empty`: an empty set of flags
87+
//! - `bits`: the raw value of the flags currently stored
88+
//! - `is_empty`: `true` if no flags are currently stored
89+
//! - `intersects`: `true` if there are flags common to both `self` and `other`
90+
//! - `contains`: `true` all of the flags in `other` are contained within `self`
91+
//! - `insert`: inserts the specified flags in-place
92+
//! - `remove`: removes the specified flags in-place
93+
94+
#[macro_export]
95+
macro_rules! bitflags(
96+
($BitFlags:ident: $T:ty {
97+
$($Flag:ident = $value:expr),+
98+
}) => (
99+
#[deriving(Eq, TotalEq, Clone)]
100+
pub struct $BitFlags {
101+
bits: $T,
102+
}
103+
104+
$(pub static $Flag: $BitFlags = $BitFlags { bits: $value };)+
105+
106+
impl $BitFlags {
107+
/// Returns an empty set of flags.
108+
pub fn empty() -> $BitFlags {
109+
$BitFlags { bits: 0 }
110+
}
111+
112+
/// Returns the raw value of the flags currently stored.
113+
pub fn bits(&self) -> $T {
114+
self.bits
115+
}
116+
117+
/// Returns `true` if no flags are currently stored.
118+
pub fn is_empty(&self) -> bool {
119+
*self == $BitFlags::empty()
120+
}
121+
122+
/// Returns `true` if there are flags common to both `self` and `other`.
123+
pub fn intersects(&self, other: $BitFlags) -> bool {
124+
!(self & other).is_empty()
125+
}
126+
127+
/// Returns `true` all of the flags in `other` are contained within `self`.
128+
pub fn contains(&self, other: $BitFlags) -> bool {
129+
(self & other) == other
130+
}
131+
132+
/// Inserts the specified flags in-place.
133+
pub fn insert(&mut self, other: $BitFlags) {
134+
self.bits |= other.bits;
135+
}
136+
137+
/// Removes the specified flags in-place.
138+
pub fn remove(&mut self, other: $BitFlags) {
139+
self.bits &= !other.bits;
140+
}
141+
}
142+
143+
impl BitOr<$BitFlags, $BitFlags> for $BitFlags {
144+
/// Returns the union of the two sets of flags.
145+
#[inline]
146+
fn bitor(&self, other: &$BitFlags) -> $BitFlags {
147+
$BitFlags { bits: self.bits | other.bits }
148+
}
149+
}
150+
151+
impl BitAnd<$BitFlags, $BitFlags> for $BitFlags {
152+
/// Returns the intersection between the two sets of flags.
153+
#[inline]
154+
fn bitand(&self, other: &$BitFlags) -> $BitFlags {
155+
$BitFlags { bits: self.bits & other.bits }
156+
}
157+
}
158+
159+
impl Sub<$BitFlags, $BitFlags> for $BitFlags {
160+
/// Returns the set difference of the two sets of flags.
161+
#[inline]
162+
fn sub(&self, other: &$BitFlags) -> $BitFlags {
163+
$BitFlags { bits: self.bits & !other.bits }
164+
}
165+
}
166+
)
167+
)
168+
169+
#[cfg(test)]
170+
mod tests {
171+
use ops::{BitOr, BitAnd, Sub};
172+
173+
bitflags!(Flags: u32 {
174+
FlagA = 0x00000001,
175+
FlagB = 0x00000010,
176+
FlagC = 0x00000100,
177+
FlagABC = FlagA.bits
178+
| FlagB.bits
179+
| FlagC.bits
180+
})
181+
182+
#[test]
183+
fn test_bits(){
184+
assert_eq!(Flags::empty().bits(), 0x00000000);
185+
assert_eq!(FlagA.bits(), 0x00000001);
186+
assert_eq!(FlagABC.bits(), 0x00000111);
187+
}
188+
189+
#[test]
190+
fn test_is_empty(){
191+
assert!(Flags::empty().is_empty());
192+
assert!(!FlagA.is_empty());
193+
assert!(!FlagABC.is_empty());
194+
}
195+
196+
#[test]
197+
fn test_two_empties_do_not_intersect() {
198+
let e1 = Flags::empty();
199+
let e2 = Flags::empty();
200+
assert!(!e1.intersects(e2));
201+
}
202+
203+
#[test]
204+
fn test_empty_does_not_intersect_with_full() {
205+
let e1 = Flags::empty();
206+
let e2 = FlagABC;
207+
assert!(!e1.intersects(e2));
208+
}
209+
210+
#[test]
211+
fn test_disjoint_intersects() {
212+
let e1 = FlagA;
213+
let e2 = FlagB;
214+
assert!(!e1.intersects(e2));
215+
}
216+
217+
#[test]
218+
fn test_overlapping_intersects() {
219+
let e1 = FlagA;
220+
let e2 = FlagA | FlagB;
221+
assert!(e1.intersects(e2));
222+
}
223+
224+
#[test]
225+
fn test_contains() {
226+
let e1 = FlagA;
227+
let e2 = FlagA | FlagB;
228+
assert!(!e1.contains(e2));
229+
assert!(e2.contains(e1));
230+
assert!(FlagABC.contains(e2));
231+
}
232+
233+
#[test]
234+
fn test_insert(){
235+
let mut e1 = FlagA;
236+
let e2 = FlagA | FlagB;
237+
e1.insert(e2);
238+
assert!(e1 == e2);
239+
}
240+
241+
#[test]
242+
fn test_remove(){
243+
let mut e1 = FlagA | FlagB;
244+
let e2 = FlagA | FlagC;
245+
e1.remove(e2);
246+
assert!(e1 == FlagB);
247+
}
248+
249+
#[test]
250+
fn test_operators() {
251+
let e1 = FlagA | FlagC;
252+
let e2 = FlagB | FlagC;
253+
assert!((e1 | e2) == FlagABC); // union
254+
assert!((e1 & e2) == FlagC); // intersection
255+
assert!((e1 - e2) == FlagA); // set difference
256+
}
257+
}

src/libstd/lib.rs

+3
Original file line numberDiff line numberDiff line change
@@ -142,7 +142,10 @@ fn start(argc: int, argv: **u8) -> int {
142142
green::start(argc, argv, rustuv::event_loop, __test::main)
143143
}
144144

145+
/* Exported macros */
146+
145147
pub mod macros;
148+
pub mod bitflags;
146149

147150
mod rtdeps;
148151

0 commit comments

Comments
 (0)