Skip to content

Commit 8b58981

Browse files
committed
Add a bitflags! macro
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 } ~~~
1 parent 33259d9 commit 8b58981

File tree

2 files changed

+223
-0
lines changed

2 files changed

+223
-0
lines changed

src/libcollections/bitflags.rs

Lines changed: 222 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,222 @@
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+
//! #[feature(phase)];
21+
//! #[phase(syntax)] extern crate collections;
22+
//!
23+
//! bitflags!(Flags: u32 {
24+
//! FlagA = 0x00000001,
25+
//! FlagB = 0x00000010,
26+
//! FlagC = 0x00000100,
27+
//! FlagABC = FlagA.bits
28+
//! | FlagB.bits
29+
//! | FlagC.bits
30+
//! })
31+
//!
32+
//! fn main() {
33+
//! let e1 = FlagA | FlagC;
34+
//! let e2 = FlagB | FlagC;
35+
//! assert!((e1 | e2) == FlagABC); // union
36+
//! assert!((e1 & e2) == FlagC); // intersection
37+
//! assert!((e1 - e2) == FlagA); // set difference
38+
//! }
39+
//! ~~~
40+
//!
41+
//! # Operators
42+
//!
43+
//! The following operator traits are implemented for the generated `struct`:
44+
//!
45+
//! - `BitOr`: union
46+
//! - `BitAnd`: intersection
47+
//! - `Sub`: set difference
48+
//!
49+
//! # Methods
50+
//!
51+
//! The following methods are defined for the generated `struct`:
52+
//!
53+
//! - `empty`: an empty set of flags
54+
//! - `bits`: the raw value of the flags currently stored
55+
//! - `is_empty`: `true` if no flags are currently stored
56+
//! - `intersects`: `true` if there are flags common to both `self` and `other`
57+
//! - `contains`: `true` all of the flags in `other` are contained within `self`
58+
//! - `insert`: inserts the specified flags in-place
59+
//! - `remove`: removes the specified flags in-place
60+
61+
#[macro_export]
62+
macro_rules! bitflags(
63+
($BitFlags:ident: $T:ty {
64+
$($Flag:ident = $value:expr),+
65+
}) => (
66+
#[deriving(Eq, TotalEq, Clone)]
67+
pub struct $BitFlags {
68+
priv bits: $T,
69+
}
70+
71+
$(pub static $Flag: $BitFlags = $BitFlags { bits: $value };)+
72+
73+
impl $BitFlags {
74+
/// Returns an empty set of flags.
75+
pub fn empty() -> $BitFlags {
76+
$BitFlags { bits: 0 }
77+
}
78+
79+
/// Returns the raw value of the flags currently stored.
80+
pub fn bits(&self) -> $T {
81+
self.bits
82+
}
83+
84+
/// Returns `true` if no flags are currently stored.
85+
pub fn is_empty(&self) -> bool {
86+
*self == $BitFlags::empty()
87+
}
88+
89+
/// Returns `true` if there are flags common to both `self` and `other`.
90+
pub fn intersects(&self, other: $BitFlags) -> bool {
91+
!(self & other).is_empty()
92+
}
93+
94+
/// Returns `true` all of the flags in `other` are contained within `self`.
95+
pub fn contains(&self, other: $BitFlags) -> bool {
96+
(self & other) == other
97+
}
98+
99+
/// Inserts the specified flags in-place.
100+
pub fn insert(&mut self, other: $BitFlags) {
101+
self.bits |= other.bits;
102+
}
103+
104+
/// Removes the specified flags in-place.
105+
pub fn remove(&mut self, other: $BitFlags) {
106+
self.bits &= !other.bits;
107+
}
108+
}
109+
110+
impl BitOr<$BitFlags, $BitFlags> for $BitFlags {
111+
/// Returns the union of the two sets of flags.
112+
#[inline]
113+
fn bitor(&self, other: &$BitFlags) -> $BitFlags {
114+
$BitFlags { bits: self.bits | other.bits }
115+
}
116+
}
117+
118+
impl BitAnd<$BitFlags, $BitFlags> for $BitFlags {
119+
/// Returns the intersection between the two sets of flags.
120+
#[inline]
121+
fn bitand(&self, other: &$BitFlags) -> $BitFlags {
122+
$BitFlags { bits: self.bits & other.bits }
123+
}
124+
}
125+
126+
impl Sub<$BitFlags, $BitFlags> for $BitFlags {
127+
/// Returns the set difference of the two sets of flags.
128+
#[inline]
129+
fn sub(&self, other: &$BitFlags) -> $BitFlags {
130+
$BitFlags { bits: self.bits & !other.bits }
131+
}
132+
}
133+
)
134+
)
135+
136+
#[cfg(test)]
137+
mod tests {
138+
bitflags!(Flags: u32 {
139+
FlagA = 0x00000001,
140+
FlagB = 0x00000010,
141+
FlagC = 0x00000100,
142+
FlagABC = FlagA.bits
143+
| FlagB.bits
144+
| FlagC.bits
145+
})
146+
147+
#[test]
148+
fn test_bits(){
149+
assert_eq!(Flags::empty().bits(), 0x00000000);
150+
assert_eq!(FlagA.bits(), 0x00000001);
151+
assert_eq!(FlagABC.bits(), 0x00000111);
152+
}
153+
154+
#[test]
155+
fn test_is_empty(){
156+
assert!(Flags::empty().is_empty());
157+
assert!(!FlagA.is_empty());
158+
assert!(!FlagABC.is_empty());
159+
}
160+
161+
#[test]
162+
fn test_two_empties_do_not_intersect() {
163+
let e1 = Flags::empty();
164+
let e2 = Flags::empty();
165+
assert!(!e1.intersects(e2));
166+
}
167+
168+
#[test]
169+
fn test_empty_does_not_intersect_with_full() {
170+
let e1 = Flags::empty();
171+
let e2 = FlagABC;
172+
assert!(!e1.intersects(e2));
173+
}
174+
175+
#[test]
176+
fn test_disjoint_intersects() {
177+
let e1 = FlagA;
178+
let e2 = FlagB;
179+
assert!(!e1.intersects(e2));
180+
}
181+
182+
#[test]
183+
fn test_overlapping_intersects() {
184+
let e1 = FlagA;
185+
let e2 = FlagA | FlagB;
186+
assert!(e1.intersects(e2));
187+
}
188+
189+
#[test]
190+
fn test_contains() {
191+
let e1 = FlagA;
192+
let e2 = FlagA | FlagB;
193+
assert!(!e1.contains(e2));
194+
assert!(e2.contains(e1));
195+
assert!(FlagABC.contains(e2));
196+
}
197+
198+
#[test]
199+
fn test_insert(){
200+
let mut e1 = FlagA;
201+
let e2 = FlagA | FlagB;
202+
e1.insert(e2);
203+
assert!(e1 == e2);
204+
}
205+
206+
#[test]
207+
fn test_remove(){
208+
let mut e1 = FlagA | FlagB;
209+
let e2 = FlagA | FlagC;
210+
e1.remove(e2);
211+
assert!(e1 == FlagB);
212+
}
213+
214+
#[test]
215+
fn test_operators() {
216+
let e1 = FlagA | FlagC;
217+
let e2 = FlagB | FlagC;
218+
assert!((e1 | e2) == FlagABC); // union
219+
assert!((e1 & e2) == FlagC); // intersection
220+
assert!((e1 - e2) == FlagA); // set difference
221+
}
222+
}

src/libcollections/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ pub use smallintmap::SmallIntMap;
4242
pub use treemap::{TreeMap, TreeSet};
4343
pub use trie::{TrieMap, TrieSet};
4444

45+
pub mod bitflags;
4546
pub mod bitv;
4647
pub mod btree;
4748
pub mod deque;

0 commit comments

Comments
 (0)