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