new_bitflags/
lib.rs

1//! More ergonomic bitflags
2
3#![deny(missing_docs)]
4
5/// Generates a bitflags type, wrapping a given primitive integer type.
6///
7/// # Example
8///
9/// The following macro invocation will create a `struct Foo`:
10///
11/// ```ignore
12/// #[macro_use] extern crate new_bitflags;
13///
14/// new_bitflags!{
15///     pub flags Foo: u32 {
16///         const flag_a = 1 << 0;
17///         const flag_b = 1 << 1;
18///         const flag_c = 1 << 2;
19///     }
20/// }
21///
22/// impl Foo {
23///     pub fn flag_abc() -> Foo {
24///         Foo::flag_a() |
25///         Foo::flag_b() |
26///         Foo::flag_c()
27///     }
28/// }
29///
30/// fn main() {
31///     let f1 = Foo::flag_a() | Foo::flag_c();
32///     let f2 = Foo::flag_b() | Foo::flag_c();
33///
34///     assert_eq!((f1 | f2), Foo::flag_abc()); // union
35///     assert_eq!((f1 & f2), Foo::flag_c());   // intersection
36///     assert_eq!((f1 - f2), Foo::flag_a());   // difference
37///     assert_eq!(!f2,       Foo::flag_a());   // complement
38/// }
39/// ```
40///
41/// The generated `struct` can be extended with type and trait `impl`s.
42///
43/// ```ignore
44/// impl Foo {
45///     pub fn is_flag_a(&self) -> bool {
46///         self.contains(Foo::flag_a())
47///     }
48/// }
49/// ```
50///
51/// # Visibility
52///
53/// The visibility of the generated `struct` can be controlled within the
54/// invocation of `new_bitflags!`
55///
56/// ```ignore
57/// #[macro_use] extern crate new_bitflags;
58///
59/// mod example {
60///     // `struct Public` will be visible outside this module.
61///     new_bitflags!{
62///         pub flags Public: u32 {
63///             // ...
64///         }
65///     }
66///
67///     // `struct Private` will not be visible outside this module.
68///     new_bitflags!{
69///         flags Private: u32 {
70///             // ...
71///         }
72///     }
73/// }
74/// ```
75///
76/// # Trait implementations
77///
78/// Generated `struct` types will have derived implementations of the following
79/// traits: `Copy`, `Clone`, `Hash`, `PartialEq`, `Eq`, `PartialOrd`, and `Ord`.
80///
81/// The traits `Extend` and `FromIterator` are implemented for sequences of
82/// `Self` and `&Self`.
83///
84/// The `Debug` trait implementation will display the set of named flags contained
85/// in a set.
86///
87/// # Operators
88///
89/// The following operators are implemented for generated `struct` types:
90///
91/// * `BitOr` and `BitOrAssign` perform union
92/// * `BitAnd` and `BitAndAssign` perform intersection
93/// * `BitXor` and `BitXorAssign` perform toggle
94/// * `Sub` and `SubAssign` perform set difference
95/// * `Not` performs set complement
96///
97/// # Methods
98///
99/// The following methods are implemented for generated `struct` types:
100///
101/// * `fn from_bits(bits) -> Option<Self>` converts from underlying bits,
102///    checking that all bits correspond to defined flags.
103/// * `fn from_bits_truncate(bits) -> Option<Self>` converts from underlying bits,
104///   truncating any bits that do not correspond to defined flags.
105/// * `fn bits(&self) -> bits` returns the underlying bits
106/// * `fn contains(&self, other: Self) -> bool` returns whether the set
107///   contains all flags present in `other`
108/// * `fn clear(&mut self)` clears all flags on the set
109/// * `fn all() -> Self` returns all defined flags
110/// * `fn empty() -> Self` returns an empty set
111/// * `fn is_all(&self) -> bool` returns whether the set contains all flags
112/// * `fn is_empty(&self) -> bool` returns whether the set is empty
113/// * `fn intersects(&self, other: Self) -> bool` returns whether any flags
114///   are common between `self` and `other`.
115/// * `fn insert(&mut self, other: Self)` inserts all flags in `other`
116/// * `fn remove(&mut self, other: Self)` removes all flags in `other`
117/// * `fn toggle(&mut self, other: Self)` toggles all flags in `other`
118/// * `fn set(&mut self, other: Self, value: bool)` sets or removes all flags
119///   in `other`, depending on boolean `value`
120///
121/// Additionally, for each defined flag, a static method of signature
122/// `fn() -> Self` is defined, returning a set containing only the named flag.
123#[macro_export]
124macro_rules! new_bitflags {
125    ( $(#[$attr:meta])* pub flags $name:ident : $inner:ty
126            { $( $(#[$flag_attr:meta])* const $flag:ident = $value:expr ; )* } ) => {
127        #[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
128        $(#[$attr])*
129        pub struct $name($inner);
130
131        new_bitflags!{ @_impl $name : $inner
132            { $( $(#[$flag_attr])* const $flag = $value ; )* } }
133    };
134    ( $(#[$attr:meta])* flags $name:ident : $inner:ty
135            { $( $(#[$flag_attr:meta])* const $flag:ident = $value:expr ; )* } ) => {
136        #[derive(Copy, Clone, Hash, Eq, PartialEq, Ord, PartialOrd)]
137        $(#[$attr])*
138        struct $name($inner);
139
140        new_bitflags!{ @_impl $name : $inner
141            { $( $(#[$flag_attr])* const $flag = $value ; )* } }
142    };
143    ( @_impl $name:ident : $inner:ty
144            { $( $(#[$flag_attr:meta])* const $flag:ident = $value:expr ; )* } ) => {
145        #[allow(dead_code)]
146        impl $name {
147            /// Converts from a set of bits, only if all set bits correspond
148            /// to defined flags.
149            #[inline]
150            pub fn from_bits(bits: $inner) -> ::std::option::Option<$name> {
151                if (bits & !$name::all().bits()) == 0 {
152                    Some($name(bits))
153                } else {
154                    None
155                }
156            }
157
158            /// Converts from a set of bits, truncating any invalid bits.
159            #[inline]
160            pub fn from_bits_truncate(bits: $inner) -> $name {
161                $name(bits) & $name::all()
162            }
163
164            /// Returns the underlying bits.
165            #[inline]
166            pub fn bits(&self) -> $inner {
167                self.0
168            }
169
170            /// Returns whether the given flags are set in `self`.
171            #[inline]
172            pub fn contains(&self, flag: $name) -> bool {
173                *self & flag == flag
174            }
175
176            /// Zeroes all bits.
177            #[inline]
178            pub fn clear(&mut self) {
179                self.0 = 0;
180            }
181
182            /// Returns the set of all defined flags.
183            #[inline]
184            pub fn all() -> $name {
185                $name(0 $( | $value )*)
186            }
187
188            /// Returns an empty set.
189            #[inline]
190            pub fn empty() -> $name {
191                $name(0)
192            }
193
194            /// Returns whether all defined flags are set in `self`.
195            #[inline]
196            pub fn is_all(&self) -> bool {
197                self == $name::all()
198            }
199
200            /// Returns whether no defined flags are set in `self`.
201            #[inline]
202            pub fn is_empty(&self) -> bool {
203                self.bits() == 0
204            }
205
206            /// Returns whether any flags contained in `other` are also
207            /// contained in `self`.
208            #[inline]
209            pub fn intersects(&self, other: $name) -> bool {
210                !(*self & other).is_empty()
211            }
212
213            /// Inserts a set of flags in-place.
214            #[inline]
215            pub fn insert(&mut self, other: $name) {
216                self.0 |= other.0;
217            }
218
219            /// Removes a set of flags in-place.
220            #[inline]
221            pub fn remove(&mut self, other: $name) {
222                self.0 &= !other.0;
223            }
224
225            /// Toggles a set of flags in-place.
226            #[inline]
227            pub fn toggle(&mut self, other: $name) {
228                self.0 ^= other.0;
229            }
230
231            /// Inserts or removes the given set of flags.
232            #[inline]
233            pub fn set(&mut self, other: $name, value: bool) {
234                if value {
235                    self.insert(other);
236                } else {
237                    self.remove(other);
238                }
239            }
240
241            $( $(#[$flag_attr])*
242            #[inline]
243            pub fn $flag() -> $name {
244                $name($value)
245            } )*
246        }
247
248        impl ::std::fmt::Debug for $name {
249            fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
250                let mut flags = *self;
251                let mut _first = true;
252
253                f.write_str(concat!(stringify!($name), "("))?;
254
255                $( if !$name::$flag().is_empty() && flags.contains($name::$flag()) {
256                    if !_first {
257                        f.write_str(" | ")?;
258                    }
259                    _first = false;
260
261                    flags.remove($name::$flag());
262                    f.write_str(stringify!($flag))?;
263                } )*
264
265                f.write_str(")")
266            }
267        }
268
269        impl ::std::iter::Extend<$name> for $name {
270            fn extend<I: ::std::iter::IntoIterator<Item=$name>>(&mut self, iter: I) {
271                for flag in iter {
272                    self.insert(flag);
273                }
274            }
275        }
276
277        impl<'a> ::std::iter::Extend<&'a $name> for $name {
278            fn extend<I: ::std::iter::IntoIterator<Item=&'a $name>>(&mut self, iter: I) {
279                for flag in iter {
280                    self.insert(*flag);
281                }
282            }
283        }
284
285        impl ::std::iter::FromIterator<$name> for $name {
286            fn from_iter<I: IntoIterator<Item=$name>>(iter: I) -> $name {
287                let mut flags = $name::empty();
288                flags.extend(iter);
289                flags
290            }
291        }
292
293        impl<'a> ::std::iter::FromIterator<&'a $name> for $name {
294            fn from_iter<I: IntoIterator<Item=&'a $name>>(iter: I) -> $name {
295                let mut flags = $name::empty();
296                flags.extend(iter);
297                flags
298            }
299        }
300
301        impl ::std::ops::BitOr for $name {
302            type Output = $name;
303
304            #[inline]
305            fn bitor(self, rhs: $name) -> $name {
306                $name(self.0 | rhs.0)
307            }
308        }
309
310        impl ::std::ops::BitOrAssign for $name {
311            #[inline]
312            fn bitor_assign(&mut self, rhs: $name) {
313                self.0 |= rhs.0;
314            }
315        }
316
317        impl ::std::ops::BitAnd for $name {
318            type Output = $name;
319
320            #[inline]
321            fn bitand(self, rhs: $name) -> $name {
322                $name(self.0 & rhs.0)
323            }
324        }
325
326        impl ::std::ops::BitAndAssign for $name {
327            #[inline]
328            fn bitand_assign(&mut self, rhs: $name) {
329                self.0 &= rhs.0;
330            }
331        }
332
333        impl ::std::ops::BitXor for $name {
334            type Output = $name;
335
336            #[inline]
337            fn bitxor(self, rhs: $name) -> $name {
338                $name(self.0 ^ rhs.0)
339            }
340        }
341
342        impl ::std::ops::BitXorAssign for $name {
343            #[inline]
344            fn bitxor_assign(&mut self, rhs: $name) {
345                self.0 ^= rhs.0;
346            }
347        }
348
349        impl ::std::ops::Not for $name {
350            type Output = $name;
351
352            #[inline]
353            fn not(self) -> $name {
354                self ^ $name::all()
355            }
356        }
357
358        impl ::std::ops::Sub for $name {
359            type Output = $name;
360
361            #[inline]
362            fn sub(mut self, rhs: $name) -> $name {
363                self.remove(rhs);
364                self
365            }
366        }
367
368        impl ::std::ops::SubAssign for $name {
369            #[inline]
370            fn sub_assign(&mut self, rhs: $name) {
371                self.remove(rhs);
372            }
373        }
374
375        impl<'a> PartialEq<&'a $name> for $name {
376            #[inline]
377            fn eq(&self, rhs: &&$name) -> bool { *self == **rhs }
378            #[inline]
379            fn ne(&self, rhs: &&$name) -> bool { *self != **rhs }
380        }
381
382        impl<'a> PartialEq<$name> for &'a $name {
383            #[inline]
384            fn eq(&self, rhs: &$name) -> bool { **self == *rhs }
385            #[inline]
386            fn ne(&self, rhs: &$name) -> bool { **self != *rhs }
387        }
388    }
389}