]> git.lizzy.rs Git - rust.git/blob - src/libstd/bitflags.rs
libstd: set baseline stability levels.
[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)]
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 option::{Some, None};
224     use ops::{BitOr, BitAnd, Sub, Not};
225
226     bitflags!(
227         flags Flags: u32 {
228             static FlagA       = 0x00000001,
229             static FlagB       = 0x00000010,
230             static FlagC       = 0x00000100,
231             static FlagABC     = FlagA.bits
232                                | FlagB.bits
233                                | FlagC.bits
234         }
235     )
236
237     #[test]
238     fn test_bits(){
239         assert_eq!(Flags::empty().bits(), 0x00000000);
240         assert_eq!(FlagA.bits(), 0x00000001);
241         assert_eq!(FlagABC.bits(), 0x00000111);
242     }
243
244     #[test]
245     fn test_from_bits() {
246         assert!(Flags::from_bits(0) == Some(Flags::empty()));
247         assert!(Flags::from_bits(0x1) == Some(FlagA));
248         assert!(Flags::from_bits(0x10) == Some(FlagB));
249         assert!(Flags::from_bits(0x11) == Some(FlagA | FlagB));
250         assert!(Flags::from_bits(0x1000) == None);
251     }
252
253     #[test]
254     fn test_from_bits_truncate() {
255         assert!(Flags::from_bits_truncate(0) == Flags::empty());
256         assert!(Flags::from_bits_truncate(0x1) == FlagA);
257         assert!(Flags::from_bits_truncate(0x10) == FlagB);
258         assert!(Flags::from_bits_truncate(0x11) == (FlagA | FlagB));
259         assert!(Flags::from_bits_truncate(0x1000) == Flags::empty());
260         assert!(Flags::from_bits_truncate(0x1001) == FlagA);
261     }
262
263     #[test]
264     fn test_is_empty(){
265         assert!(Flags::empty().is_empty());
266         assert!(!FlagA.is_empty());
267         assert!(!FlagABC.is_empty());
268     }
269
270     #[test]
271     fn test_is_all() {
272         assert!(Flags::all().is_all());
273         assert!(!FlagA.is_all());
274         assert!(FlagABC.is_all());
275     }
276
277     #[test]
278     fn test_two_empties_do_not_intersect() {
279         let e1 = Flags::empty();
280         let e2 = Flags::empty();
281         assert!(!e1.intersects(e2));
282     }
283
284     #[test]
285     fn test_empty_does_not_intersect_with_full() {
286         let e1 = Flags::empty();
287         let e2 = FlagABC;
288         assert!(!e1.intersects(e2));
289     }
290
291     #[test]
292     fn test_disjoint_intersects() {
293         let e1 = FlagA;
294         let e2 = FlagB;
295         assert!(!e1.intersects(e2));
296     }
297
298     #[test]
299     fn test_overlapping_intersects() {
300         let e1 = FlagA;
301         let e2 = FlagA | FlagB;
302         assert!(e1.intersects(e2));
303     }
304
305     #[test]
306     fn test_contains() {
307         let e1 = FlagA;
308         let e2 = FlagA | FlagB;
309         assert!(!e1.contains(e2));
310         assert!(e2.contains(e1));
311         assert!(FlagABC.contains(e2));
312     }
313
314     #[test]
315     fn test_insert(){
316         let mut e1 = FlagA;
317         let e2 = FlagA | FlagB;
318         e1.insert(e2);
319         assert!(e1 == e2);
320     }
321
322     #[test]
323     fn test_remove(){
324         let mut e1 = FlagA | FlagB;
325         let e2 = FlagA | FlagC;
326         e1.remove(e2);
327         assert!(e1 == FlagB);
328     }
329
330     #[test]
331     fn test_operators() {
332         let e1 = FlagA | FlagC;
333         let e2 = FlagB | FlagC;
334         assert!((e1 | e2) == FlagABC);   // union
335         assert!((e1 & e2) == FlagC);     // intersection
336         assert!((e1 - e2) == FlagA);     // set difference
337         assert!(!e2 == FlagA);           // set complement
338     }
339 }