]> git.lizzy.rs Git - rust.git/blob - src/libstd/bitflags.rs
Derive PartialOrd, Ord and Hash for bitflags types.
[rust.git] / src / libstd / bitflags.rs
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!(
21 //!     flags Flags: u32 {
22 //!         static FlagA       = 0x00000001,
23 //!         static FlagB       = 0x00000010,
24 //!         static FlagC       = 0x00000100,
25 //!         static FlagABC     = FlagA.bits
26 //!                            | FlagB.bits
27 //!                            | FlagC.bits
28 //!     }
29 //! )
30 //!
31 //! fn main() {
32 //!     let e1 = FlagA | FlagC;
33 //!     let e2 = FlagB | FlagC;
34 //!     assert!((e1 | e2) == FlagABC);   // union
35 //!     assert!((e1 & e2) == FlagC);     // intersection
36 //!     assert!((e1 - e2) == FlagA);     // set difference
37 //!     assert!(!e2 == FlagA);           // set complement
38 //! }
39 //! ~~~
40 //!
41 //! The generated `struct`s can also be extended with type and trait implementations:
42 //!
43 //! ~~~rust
44 //! use std::fmt;
45 //!
46 //! bitflags!(
47 //!     flags Flags: u32 {
48 //!         static FlagA   = 0x00000001,
49 //!         static FlagB   = 0x00000010
50 //!     }
51 //! )
52 //!
53 //! impl Flags {
54 //!     pub fn clear(&mut self) {
55 //!         self.bits = 0;  // The `bits` field can be accessed from within the
56 //!                         // same module where the `bitflags!` macro was invoked.
57 //!     }
58 //! }
59 //!
60 //! impl fmt::Show for Flags {
61 //!     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
62 //!         write!(f, "hi!")
63 //!     }
64 //! }
65 //!
66 //! fn main() {
67 //!     let mut flags = FlagA | FlagB;
68 //!     flags.clear();
69 //!     assert!(flags.is_empty());
70 //!     assert_eq!(format!("{}", flags).as_slice(), "hi!");
71 //! }
72 //! ~~~
73 //!
74 //! # Attributes
75 //!
76 //! Attributes can be attached to the generated `struct` by placing them
77 //! before the `flags` keyword.
78 //!
79 //! # Derived traits
80 //!
81 //! The `PartialEq` and `Clone` traits are automatically derived for the `struct` using
82 //! the `deriving` attribute. Additional traits can be derived by providing an
83 //! explicit `deriving` attribute on `flags`.
84 //!
85 //! # Operators
86 //!
87 //! The following operator traits are implemented for the generated `struct`:
88 //!
89 //! - `BitOr`: union
90 //! - `BitAnd`: intersection
91 //! - `Sub`: set difference
92 //! - `Not`: set complement
93 //!
94 //! # Methods
95 //!
96 //! The following methods are defined for the generated `struct`:
97 //!
98 //! - `empty`: an empty set of flags
99 //! - `all`: the set of all flags
100 //! - `bits`: the raw value of the flags currently stored
101 //! - `is_empty`: `true` if no flags are currently stored
102 //! - `is_all`: `true` if all flags are currently set
103 //! - `intersects`: `true` if there are flags common to both `self` and `other`
104 //! - `contains`: `true` all of the flags in `other` are contained within `self`
105 //! - `insert`: inserts the specified flags in-place
106 //! - `remove`: removes the specified flags in-place
107
108 #![experimental]
109 #![macro_escape]
110
111 #[macro_export]
112 macro_rules! bitflags(
113     ($(#[$attr:meta])* flags $BitFlags:ident: $T:ty {
114         $($(#[$Flag_attr:meta])* static $Flag:ident = $value:expr),+
115     }) => (
116         #[deriving(PartialEq, Eq, Clone, PartialOrd, Ord, Hash)]
117         $(#[$attr])*
118         pub struct $BitFlags {
119             bits: $T,
120         }
121
122         $($(#[$Flag_attr])* pub static $Flag: $BitFlags = $BitFlags { bits: $value };)+
123
124         impl $BitFlags {
125             /// Returns an empty set of flags.
126             pub fn empty() -> $BitFlags {
127                 $BitFlags { bits: 0 }
128             }
129
130             /// Returns the set containing all flags.
131             pub fn all() -> $BitFlags {
132                 $BitFlags { bits: $($value)|+ }
133             }
134
135             /// Returns the raw value of the flags currently stored.
136             pub fn bits(&self) -> $T {
137                 self.bits
138             }
139
140             /// Convert from underlying bit representation, unless that
141             /// representation contains bits that do not correspond to a flag.
142             pub fn from_bits(bits: $T) -> ::std::option::Option<$BitFlags> {
143                 if (bits & !$BitFlags::all().bits()) != 0 {
144                     ::std::option::None
145                 } else {
146                     ::std::option::Some($BitFlags { bits: bits })
147                 }
148             }
149
150             /// Convert from underlying bit representation, dropping any bits
151             /// that do not correspond to flags.
152             pub fn from_bits_truncate(bits: $T) -> $BitFlags {
153                 $BitFlags { bits: bits } & $BitFlags::all()
154             }
155
156             /// Returns `true` if no flags are currently stored.
157             pub fn is_empty(&self) -> bool {
158                 *self == $BitFlags::empty()
159             }
160
161             /// Returns `true` if all flags are currently set.
162             pub fn is_all(&self) -> bool {
163                 *self == $BitFlags::all()
164             }
165
166             /// Returns `true` if there are flags common to both `self` and `other`.
167             pub fn intersects(&self, other: $BitFlags) -> bool {
168                 !(self & other).is_empty()
169             }
170
171             /// Returns `true` all of the flags in `other` are contained within `self`.
172             pub fn contains(&self, other: $BitFlags) -> bool {
173                 (self & other) == other
174             }
175
176             /// Inserts the specified flags in-place.
177             pub fn insert(&mut self, other: $BitFlags) {
178                 self.bits |= other.bits;
179             }
180
181             /// Removes the specified flags in-place.
182             pub fn remove(&mut self, other: $BitFlags) {
183                 self.bits &= !other.bits;
184             }
185         }
186
187         impl BitOr<$BitFlags, $BitFlags> for $BitFlags {
188             /// Returns the union of the two sets of flags.
189             #[inline]
190             fn bitor(&self, other: &$BitFlags) -> $BitFlags {
191                 $BitFlags { bits: self.bits | other.bits }
192             }
193         }
194
195         impl BitAnd<$BitFlags, $BitFlags> for $BitFlags {
196             /// Returns the intersection between the two sets of flags.
197             #[inline]
198             fn bitand(&self, other: &$BitFlags) -> $BitFlags {
199                 $BitFlags { bits: self.bits & other.bits }
200             }
201         }
202
203         impl Sub<$BitFlags, $BitFlags> for $BitFlags {
204             /// Returns the set difference of the two sets of flags.
205             #[inline]
206             fn sub(&self, other: &$BitFlags) -> $BitFlags {
207                 $BitFlags { bits: self.bits & !other.bits }
208             }
209         }
210
211         impl Not<$BitFlags> for $BitFlags {
212             /// Returns the complement of this set of flags.
213             #[inline]
214             fn not(&self) -> $BitFlags {
215                 $BitFlags { bits: !self.bits } & $BitFlags::all()
216             }
217         }
218     )
219 )
220
221 #[cfg(test)]
222 mod tests {
223     use hash;
224     use option::{Some, None};
225     use ops::{BitOr, BitAnd, Sub, Not};
226
227     bitflags!(
228         flags Flags: u32 {
229             static FlagA       = 0x00000001,
230             static FlagB       = 0x00000010,
231             static FlagC       = 0x00000100,
232             static FlagABC     = FlagA.bits
233                                | FlagB.bits
234                                | FlagC.bits
235         }
236     )
237
238     #[test]
239     fn test_bits(){
240         assert_eq!(Flags::empty().bits(), 0x00000000);
241         assert_eq!(FlagA.bits(), 0x00000001);
242         assert_eq!(FlagABC.bits(), 0x00000111);
243     }
244
245     #[test]
246     fn test_from_bits() {
247         assert!(Flags::from_bits(0) == Some(Flags::empty()));
248         assert!(Flags::from_bits(0x1) == Some(FlagA));
249         assert!(Flags::from_bits(0x10) == Some(FlagB));
250         assert!(Flags::from_bits(0x11) == Some(FlagA | FlagB));
251         assert!(Flags::from_bits(0x1000) == None);
252     }
253
254     #[test]
255     fn test_from_bits_truncate() {
256         assert!(Flags::from_bits_truncate(0) == Flags::empty());
257         assert!(Flags::from_bits_truncate(0x1) == FlagA);
258         assert!(Flags::from_bits_truncate(0x10) == FlagB);
259         assert!(Flags::from_bits_truncate(0x11) == (FlagA | FlagB));
260         assert!(Flags::from_bits_truncate(0x1000) == Flags::empty());
261         assert!(Flags::from_bits_truncate(0x1001) == FlagA);
262     }
263
264     #[test]
265     fn test_is_empty(){
266         assert!(Flags::empty().is_empty());
267         assert!(!FlagA.is_empty());
268         assert!(!FlagABC.is_empty());
269     }
270
271     #[test]
272     fn test_is_all() {
273         assert!(Flags::all().is_all());
274         assert!(!FlagA.is_all());
275         assert!(FlagABC.is_all());
276     }
277
278     #[test]
279     fn test_two_empties_do_not_intersect() {
280         let e1 = Flags::empty();
281         let e2 = Flags::empty();
282         assert!(!e1.intersects(e2));
283     }
284
285     #[test]
286     fn test_empty_does_not_intersect_with_full() {
287         let e1 = Flags::empty();
288         let e2 = FlagABC;
289         assert!(!e1.intersects(e2));
290     }
291
292     #[test]
293     fn test_disjoint_intersects() {
294         let e1 = FlagA;
295         let e2 = FlagB;
296         assert!(!e1.intersects(e2));
297     }
298
299     #[test]
300     fn test_overlapping_intersects() {
301         let e1 = FlagA;
302         let e2 = FlagA | FlagB;
303         assert!(e1.intersects(e2));
304     }
305
306     #[test]
307     fn test_contains() {
308         let e1 = FlagA;
309         let e2 = FlagA | FlagB;
310         assert!(!e1.contains(e2));
311         assert!(e2.contains(e1));
312         assert!(FlagABC.contains(e2));
313     }
314
315     #[test]
316     fn test_insert(){
317         let mut e1 = FlagA;
318         let e2 = FlagA | FlagB;
319         e1.insert(e2);
320         assert!(e1 == e2);
321     }
322
323     #[test]
324     fn test_remove(){
325         let mut e1 = FlagA | FlagB;
326         let e2 = FlagA | FlagC;
327         e1.remove(e2);
328         assert!(e1 == FlagB);
329     }
330
331     #[test]
332     fn test_operators() {
333         let e1 = FlagA | FlagC;
334         let e2 = FlagB | FlagC;
335         assert!((e1 | e2) == FlagABC);   // union
336         assert!((e1 & e2) == FlagC);     // intersection
337         assert!((e1 - e2) == FlagA);     // set difference
338         assert!(!e2 == FlagA);           // set complement
339     }
340
341     #[test]
342     fn test_lt() {
343         let mut a = Flags::empty();
344         let mut b = Flags::empty();
345
346         assert!(!(a < b) && !(b < a));
347         b = FlagB;
348         assert!(a < b);
349         a = FlagC;
350         assert!(!(a < b) && b < a);
351         b = FlagC | FlagB;
352         assert!(a < b);
353     }
354
355     #[test]
356     fn test_ord() {
357         let mut a = Flags::empty();
358         let mut b = Flags::empty();
359
360         assert!(a <= b && a >= b);
361         a = FlagA;
362         assert!(a > b && a >= b);
363         assert!(b < a && b <= a);
364         b = FlagB;
365         assert!(b > a && b >= a);
366         assert!(a < b && a <= b);
367     }
368
369     #[test]
370     fn test_hash() {
371       let mut x = Flags::empty();
372       let mut y = Flags::empty();
373       assert!(hash::hash(&x) == hash::hash(&y));
374       x = Flags::all();
375       y = FlagABC;
376       assert!(hash::hash(&x) == hash::hash(&y));
377     }
378 }