/// Creates a Flag type that is also very useful for working with C FFIs. #[macro_export] macro_rules! c_flags { { $(#[$attribute: meta])* flags $name: ident : $fieldType: ty { $( $(#[$flagAttribute: meta])* const $flag: ident = $value: expr ),+ } } => { // Create the structure that will represent the bitflag. // Derive the basic needed functionality and // add any required extra attributes. $(#[$attribute])* #[derive(Clone, Copy, Eq, PartialEq, PartialOrd, Ord, Hash)] pub struct $name { bits: $fieldType } $($(#[$flagAttribute])* pub const $flag: $name = $name {bits: $value};)+ impl $name { /// Create a new default version of the /// bitflag structure. pub fn new() -> $name { $name::empty() } /// Create a new bitflag structure from /// the given bits. pub fn from_bits(bits: $fieldType) -> Option<$name> { if bits & !$name::all().get_bits() != 0 { None } else { Some($name {bits: bits}) } } /// Returns an empty set of flags. #[inline] pub fn empty() -> $name { $name {bits: 0} } /// Returns the set containing all flags. pub fn all() -> $name { $name {bits: $($flag.bits)|+} } /// Returns `true` if no flags are currently stored; /// Otherwise, `false` is returned. pub fn is_empty(&self) -> bool { *self == $name::empty() } /// Returns `true` if all the flags are currently set; /// Otherwise, `false` is returned. pub fn is_all(&self) -> bool { *self == $name::all() } /// Returns the raw value of the flags currently stored. pub fn get_bits(&self) -> $fieldType { self.bits } /// Turn the flag into a String representation of its self. #[warn(unused_assignments)] pub fn to_string(&self) -> String { let mut first: bool; let mut string: String; // Push the left bracket onto the string. string = String::new(); string.push_str("{"); // Handle checking each flag to see if it // is part of this flag. first = true; $( if self.intersects($flag) == true { // If this is not the first flag, // then add an OR symbol. if first == false { string.push_str(" | "); } // Push the flags name onto the string. string.push_str(stringify!($flag)); first = false; } )+ // No flags were set. if first == true { // Put a space in the string. string.push_str(" "); } // Push the right bracket onto the string // and return it. string.push_str("}"); string } /// Returns `true` if there are flags common to /// both `self` and `other`; Otherwise, `false` is returned. pub fn intersects(&self, other: $name) -> bool { !(*self & other).is_empty() } /// Returns `true` all of the flags in `other` are /// contained within `self`; Otherwise, `false` is returned. pub fn contains(&self, other: $name) -> bool { (*self & other) == other } /// Inserts the specified flags in-place. pub fn insert(&mut self, other: $name) { self.bits |= other.bits; } /// Removes the specified flags in-place. pub fn remove(&mut self, other: $name) { self.bits &= !other.bits; } /// Toggles the specified flags in-place. pub fn toggle(&mut self, other: $name) { self.bits ^= other.bits; } } impl ::std::ops::BitOr for $name { type Output = $name; /// Returns the union of the two sets of flags. fn bitor(self, other: $name) -> $name { $name {bits: self.bits | other.bits} } } impl ::std::ops::BitXor for $name { type Output = $name; /// Returns the left flags, but with all the right flags toggled. fn bitxor(self, other: $name) -> $name { $name {bits: self.bits ^ other.bits} } } impl ::std::ops::BitAnd for $name { type Output = $name; /// Returns the intersection between the two sets of flags. fn bitand(self, other: $name) -> $name { $name {bits: self.bits & other.bits} } } impl ::std::ops::Sub for $name { type Output = $name; /// Returns the set difference of the two sets of flags. fn sub(self, other: $name) -> $name { $name {bits: self.bits & !other.bits} } } impl ::std::ops::Not for $name { type Output = $name; /// Returns the complement of this set of flags. fn not(self) -> $name { $name {bits: !self.bits} & $name::all() } } impl ::std::fmt::Debug for $name { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "{}", self.to_string()) } } impl ::std::fmt::Display for $name { fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { write!(f, "{}", self.to_string()) } } } }