|
| 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 | +} |
0 commit comments