binding/src/c_flags.rs

233 lines
6.0 KiB
Rust
Raw Normal View History

2017-01-06 19:10:10 -05:00
/// 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())
}
}
}
}