binding/src/c_flags.rs
Jason Travis Smith 8b5d5a9c57 Adjusting the Display implementation.
Display will automatically implement the to_string functionality, so the
explicit implementation was removed.
2017-05-11 16:49:46 -04:00

224 lines
5.7 KiB
Rust

/// 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
}
/// 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
{
::std::fmt::Display::fmt(self, f)
}
}
impl ::std::fmt::Display for $name
{
#[warn(unused_assignments)]
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result
{
let mut first: bool;
// Push the left bracket onto the string.
try!(write!(f, "{}", '{'));
// 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
{
try!(write!(f, " | "));
}
// Push the flags name onto the string.
try!(write!(f, "{}", stringify!($flag)));
first = false;
}
)+
// No flags were set.
if first == true
{
// Put a space in the string.
try!(write!(f, " "));
}
// Push the right bracket onto the string
// and return it.
write!(f, "{}", '}')
}
}
}
}