233 lines
6.0 KiB
Rust
233 lines
6.0 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
|
||
|
}
|
||
|
|
||
|
/// 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())
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|