It\'s possible to declare flags in Rust - similar to how it would be done in C.
pub const FOO: u32 = (1 << 0);
pub const BAR: u32 = (1 << 1);
let fl
Posting answer which uses a macro as one possible solution to the question.
Example usage:
struct_bitflag_impl!(pub struct MyFlag(pub u8));
pub struct MyFlag(u8);
struct_bitflag_impl!(MyFlag);
pub struct MyOtherFlag(u32);
struct_bitflag_impl!(MyOtherFlag);
value.0
if needed.struct_bitflag_impl
which can be re-used and applied to multiple struct types.The macro:
/// Implements bitflag operators for integer struct, eg:
/// ```
/// pub struct MyFlag(u8);
/// struct_bitflag_impl!(MyFlag);
/// ```
macro_rules! struct_bitflag_impl {
($p:ident) => {
// Possible additions:
// * left/right shift.
// * Deref to forward methods to the underlying type.
impl ::std::ops::BitAnd for $p {
type Output = $p;
fn bitand(self, _rhs: $p) -> $p { $p(self.0 & _rhs.0) }
}
impl ::std::ops::BitOr for $p {
type Output = $p;
fn bitor(self, _rhs: $p) -> $p { $p(self.0 | _rhs.0) }
}
impl ::std::ops::BitXor for $p {
type Output = $p;
fn bitxor(self, _rhs: $p) -> $p { $p(self.0 ^ _rhs.0) }
}
impl ::std::ops::Not for $p {
type Output = $p;
fn not(self) -> $p { $p(!self.0) }
}
impl ::std::ops::BitAndAssign for $p {
fn bitand_assign(&mut self, _rhs: $p) { self.0 &= _rhs.0; }
}
impl ::std::ops::BitOrAssign for $p {
fn bitor_assign(&mut self, _rhs: $p) { self.0 |= _rhs.0; }
}
impl ::std::ops::BitXorAssign for $p {
fn bitxor_assign(&mut self, _rhs: $p) { self.0 ^= _rhs.0; }
}
// Other operations needed to be generally usable.
impl PartialEq for $p {
fn eq(&self, other: &$p) -> bool { self.0 == other.0 }
}
impl Copy for $p { }
impl Clone for $p {
fn clone(&self) -> $p { $p(self.0) }
}
}
}
For an alternative variation on this macro that supports derive
which is needed so constants of this type can be used in a match
statement can be written.
This also avoids having to define Copy & Clone.
struct_bitflag_impl!(pub struct MyFlag(pub u8));
The macro:
macro_rules! struct_bitflag_impl {
// pub/pub
(pub struct $name:ident ( pub $t:tt ) ) => {
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
pub struct $name(pub $t);
_struct_bitflag_gen_impls!($name, $t);
};
// private/pub
(struct $name:ident ( pub $t:tt ) ) => {
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
struct $name(pub $t);
_struct_bitflag_gen_impls!($name, $t);
};
// pub/private
(pub struct $name:ident ( $t:tt ) ) => {
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
struct $name($t);
_struct_bitflag_gen_impls!($name, $t);
};
// private/private
(struct $name:ident ( $t:tt ) ) => {
#[derive(PartialEq, Eq, Copy, Clone, Debug)]
struct $name($t);
_struct_bitflag_gen_impls!($name, $t);
}
}
macro_rules! _struct_bitflag_gen_impls {
($t:ident, $t_base:ident) => {
impl ::std::ops::BitAnd for $t {
type Output = $t;
#[inline]
fn bitand(self, _rhs: $t) -> $t { $t(self.0 & _rhs.0) }
}
impl ::std::ops::BitOr for $t {
type Output = $t;
#[inline]
fn bitor(self, _rhs: $t) -> $t { $t(self.0 | _rhs.0) }
}
impl ::std::ops::BitXor for $t {
type Output = $t;
#[inline]
fn bitxor(self, _rhs: $t) -> $t { $t(self.0 ^ _rhs.0) }
}
impl ::std::ops::Not for $t {
type Output = $t;
#[inline]
fn not(self) -> $t { $t(!self.0) }
}
impl ::std::ops::BitAndAssign for $t {
#[inline]
fn bitand_assign(&mut self, _rhs: $t) { self.0 &= _rhs.0; }
}
impl ::std::ops::BitOrAssign for $t {
#[inline]
fn bitor_assign(&mut self, _rhs: $t) { self.0 |= _rhs.0; }
}
impl ::std::ops::BitXorAssign for $t {
#[inline]
fn bitxor_assign(&mut self, _rhs: $t) { self.0 ^= _rhs.0; }
}
/// Support for comparing with the base type, allows comparison with 0.
///
/// This is used in typical expressions, eg: `if (a & FLAG) != 0 { ... }`
/// Having to use MyFlag(0) all over is too inconvenient.
impl PartialEq<$t_base> for $t {
#[inline]
fn eq(&self, other: &$t_base) -> bool { self.0 == *other }
}
}
}