#![cfg_attr(
feature = "serde",
doc = r#"
## Optional Serde support
[Serde] support can be enabled with the 'serde' feature flag. You can then serialize and
deserialize `FlagSet<T>` to and from any of the [supported formats]:
```
use flagset::{FlagSet, flags};
flags! {
enum Flags: u8 {
Foo,
Bar,
}
}
let flagset = Flags::Foo | Flags::Bar;
let json = serde_json::to_string(&flagset).unwrap();
let flagset: FlagSet<Flags> = serde_json::from_str(&json).unwrap();
assert_eq!(flagset.bits(), 0b011);
```
For serialization and deserialization of flags enum itself, you can use the [`serde_repr`] crate
(or implement `serde::ser::Serialize` and `serde:de::Deserialize` manually), combined with the
appropriate `repr` attribute:
```
use flagset::{FlagSet, flags};
use serde_repr::{Serialize_repr, Deserialize_repr};
flags! {
#[repr(u8)]
#[derive(Deserialize_repr, Serialize_repr)]
enum Flags: u8 {
Foo,
Bar,
}
}
let json = serde_json::to_string(&Flags::Foo).unwrap();
let flag: Flags = serde_json::from_str(&json).unwrap();
assert_eq!(flag, Flags::Foo);
```
[Serde]: https://serde.rs/
[supported formats]: https://serde.rs/#data-formats
[`serde_repr`]: https://crates.io/crates/serde_repr
"#
)]
#![allow(unknown_lints)]
#![warn(clippy::all)]
#![cfg_attr(not(feature = "std"), no_std)]
#![cfg_attr(docsrs, feature(doc_auto_cfg))]
use core::fmt::{Debug, Formatter, Result};
use core::ops::*;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub struct InvalidBits;
impl core::fmt::Display for InvalidBits {
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "invalid bits")
}
}
#[cfg(feature = "std")]
impl std::error::Error for InvalidBits {}
#[doc(hidden)]
pub trait Flags:
Copy
+ Clone
+ Debug
+ PartialEq
+ Eq
+ BitAnd<Self, Output = FlagSet<Self>>
+ BitOr<Self, Output = FlagSet<Self>>
+ BitXor<Self, Output = FlagSet<Self>>
+ Sub<Self, Output = FlagSet<Self>>
+ Rem<Self, Output = FlagSet<Self>>
+ Not<Output = FlagSet<Self>>
+ Into<FlagSet<Self>>
+ 'static
{
type Type: Copy
+ Clone
+ Debug
+ PartialEq
+ Eq
+ Default
+ BitAnd<Self::Type, Output = Self::Type>
+ BitAndAssign<Self::Type>
+ BitOr<Self::Type, Output = Self::Type>
+ BitOrAssign<Self::Type>
+ BitXor<Self::Type, Output = Self::Type>
+ BitXorAssign<Self::Type>
+ Not<Output = Self::Type>;
const ZERO: Self::Type;
const LIST: &'static [Self];
#[inline]
fn none() -> FlagSet<Self> {
FlagSet::empty()
}
}
#[repr(C)]
#[derive(Copy, Clone, Eq, Hash)]
pub struct FlagSet<F: Flags>(F::Type);
#[doc(hidden)]
#[derive(Copy, Clone)]
pub struct Iter<F: Flags>(FlagSet<F>, usize);
impl<F: Flags> Iterator for Iter<F> {
type Item = F;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
while self.1 < F::LIST.len() {
let next = F::LIST[self.1];
self.1 += 1;
if self.0.contains(next) {
return Some(next);
}
}
None
}
}
impl<F: Flags> IntoIterator for FlagSet<F> {
type Item = F;
type IntoIter = Iter<F>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
Iter(self, 0)
}
}
impl<F: Flags> Debug for FlagSet<F> {
#[inline]
fn fmt(&self, f: &mut Formatter) -> Result {
write!(f, "FlagSet(")?;
for (i, flag) in self.into_iter().enumerate() {
write!(f, "{}{:?}", if i > 0 { " | " } else { "" }, flag)?;
}
write!(f, ")")
}
}
impl<F: Flags, R: Copy + Into<FlagSet<F>>> PartialEq<R> for FlagSet<F> {
#[inline]
fn eq(&self, rhs: &R) -> bool {
self.0 == (*rhs).into().0
}
}
impl<F: Flags> AsRef<F::Type> for FlagSet<F> {
#[inline]
fn as_ref(&self) -> &F::Type {
&self.0
}
}
impl<F: Flags> From<Option<FlagSet<F>>> for FlagSet<F> {
#[inline]
fn from(value: Option<FlagSet<F>>) -> FlagSet<F> {
value.unwrap_or_default()
}
}
impl<F: Flags> Default for FlagSet<F> {
#[inline]
fn default() -> Self {
Self::empty()
}
}
impl<F: Flags> Not for FlagSet<F> {
type Output = Self;
#[inline]
fn not(self) -> Self {
FlagSet(!self.0)
}
}
impl<F: Flags, R: Into<FlagSet<F>>> BitAnd<R> for FlagSet<F> {
type Output = Self;
#[inline]
fn bitand(self, rhs: R) -> Self {
FlagSet(self.0 & rhs.into().0)
}
}
impl<F: Flags, R: Into<FlagSet<F>>> BitAndAssign<R> for FlagSet<F> {
#[inline]
fn bitand_assign(&mut self, rhs: R) {
self.0 &= rhs.into().0
}
}
impl<F: Flags, R: Into<FlagSet<F>>> BitOr<R> for FlagSet<F> {
type Output = Self;
#[inline]
fn bitor(self, rhs: R) -> Self {
FlagSet(self.0 | rhs.into().0)
}
}
impl<F: Flags, R: Into<FlagSet<F>>> BitOrAssign<R> for FlagSet<F> {
#[inline]
fn bitor_assign(&mut self, rhs: R) {
self.0 |= rhs.into().0
}
}
impl<F: Flags, R: Into<FlagSet<F>>> BitXor<R> for FlagSet<F> {
type Output = Self;
#[inline]
fn bitxor(self, rhs: R) -> Self {
FlagSet(self.0 ^ rhs.into().0)
}
}
impl<F: Flags, R: Into<FlagSet<F>>> BitXorAssign<R> for FlagSet<F> {
#[inline]
fn bitxor_assign(&mut self, rhs: R) {
self.0 ^= rhs.into().0
}
}
impl<F: Flags, R: Into<FlagSet<F>>> Sub<R> for FlagSet<F> {
type Output = Self;
#[inline]
fn sub(self, rhs: R) -> Self {
self & !rhs.into()
}
}
impl<F: Flags, R: Into<FlagSet<F>>> SubAssign<R> for FlagSet<F> {
#[inline]
fn sub_assign(&mut self, rhs: R) {
*self &= !rhs.into();
}
}
impl<F: Flags, R: Into<FlagSet<F>>> Rem<R> for FlagSet<F> {
type Output = Self;
#[inline]
fn rem(self, rhs: R) -> Self {
let rhs = rhs.into();
(self - rhs) | (rhs - self)
}
}
impl<F: Flags, R: Into<FlagSet<F>>> RemAssign<R> for FlagSet<F> {
#[inline]
fn rem_assign(&mut self, rhs: R) {
*self = *self % rhs
}
}
impl<F: Flags, R: Into<FlagSet<F>>> Extend<R> for FlagSet<F> {
fn extend<T>(&mut self, iter: T)
where
T: IntoIterator<Item = R>,
{
for item in iter {
*self |= item;
}
}
}
impl<F: Flags> FlagSet<F> {
#[inline]
pub fn new(bits: F::Type) -> core::result::Result<Self, InvalidBits> {
if Self::new_truncated(bits).0 == bits {
return Ok(FlagSet(bits));
}
Err(InvalidBits)
}
#[inline]
pub fn new_truncated(bits: F::Type) -> Self {
let mut set = Self::default();
for flag in FlagSet::<F>(bits) {
set |= flag;
}
set
}
#[inline]
pub const unsafe fn new_unchecked(bits: F::Type) -> Self {
FlagSet(bits)
}
#[inline]
pub const fn empty() -> Self {
FlagSet(F::ZERO)
}
#[inline]
pub fn full() -> Self {
let mut set = Self::default();
for f in F::LIST {
set |= *f
}
set
}
#[inline]
pub fn bits(self) -> F::Type {
self.0
}
#[inline]
pub fn is_empty(self) -> bool {
self == Self::default()
}
#[inline]
pub fn is_full(self) -> bool {
self == Self::full()
}
#[inline]
pub fn is_disjoint(self, rhs: impl Into<FlagSet<F>>) -> bool {
self & rhs == Self::default()
}
#[inline]
pub fn contains(self, rhs: impl Into<FlagSet<F>>) -> bool {
let rhs = rhs.into();
self & rhs == rhs
}
#[inline]
pub fn clear(&mut self) {
*self = Self::default();
}
#[inline]
pub fn drain(&mut self) -> Iter<F> {
let iter = self.into_iter();
*self = Self::default();
iter
}
#[inline]
pub fn retain(&mut self, func: impl Fn(F) -> bool) {
for f in self.into_iter() {
if !func(f) {
*self -= f
}
}
}
}
#[cfg(feature = "serde")]
impl<F: Flags> serde::Serialize for FlagSet<F>
where
F::Type: serde::ser::Serialize,
{
#[inline]
fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
where
S: serde::ser::Serializer,
{
self.0.serialize(serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, F: Flags> serde::Deserialize<'de> for FlagSet<F>
where
F::Type: serde::de::Deserialize<'de>,
{
#[inline]
fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
where
D: serde::de::Deserializer<'de>,
{
Ok(FlagSet(F::Type::deserialize(deserializer)?))
}
}
#[macro_export]
macro_rules! flags {
() => {};
($(#[$m:meta])* $p:vis enum $n:ident: $t:ty { $($(#[$a:meta])* $k:ident),+ $(,)* } $($next:tt)*) => {
$crate::flags! { $(#[$m])* $p enum $n: $t { $($(#[$a])* $k = (1 << $n::$k as $t)),+ } $($next)* }
};
($(#[$m:meta])* $p:vis enum $n:ident: $t:ty { $($(#[$a:meta])*$k:ident = $v:expr),* $(,)* } $($next:tt)*) => {
$(#[$m])*
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
$p enum $n { $($(#[$a])* $k),* }
impl $crate::Flags for $n {
type Type = $t;
const ZERO: Self::Type = 0;
const LIST: &'static [Self] = &[$($n::$k),*];
}
impl ::core::convert::From<$n> for $crate::FlagSet<$n> {
#[inline]
fn from(value: $n) -> Self {
unsafe {
match value {
$($n::$k => Self::new_unchecked($v)),*
}
}
}
}
impl ::core::ops::Not for $n {
type Output = $crate::FlagSet<$n>;
#[inline]
fn not(self) -> Self::Output {
!$crate::FlagSet::from(self)
}
}
impl<R: ::core::convert::Into<$crate::FlagSet<$n>>> ::core::ops::BitAnd<R> for $n {
type Output = $crate::FlagSet<$n>;
#[inline]
fn bitand(self, rhs: R) -> Self::Output {
$crate::FlagSet::from(self) & rhs
}
}
impl<R: ::core::convert::Into<$crate::FlagSet<$n>>> ::core::ops::BitOr<R> for $n {
type Output = $crate::FlagSet<$n>;
#[inline]
fn bitor(self, rhs: R) -> Self::Output {
$crate::FlagSet::from(self) | rhs
}
}
impl<R: ::core::convert::Into<$crate::FlagSet<$n>>> ::core::ops::BitXor<R> for $n {
type Output = $crate::FlagSet<$n>;
#[inline]
fn bitxor(self, rhs: R) -> Self::Output {
$crate::FlagSet::from(self) ^ rhs
}
}
impl<R: ::core::convert::Into<$crate::FlagSet<$n>>> ::core::ops::Sub<R> for $n {
type Output = $crate::FlagSet<$n>;
#[inline]
fn sub(self, rhs: R) -> Self::Output {
$crate::FlagSet::from(self) - rhs
}
}
impl<R: ::core::convert::Into<$crate::FlagSet<$n>>> ::core::ops::Rem<R> for $n {
type Output = $crate::FlagSet<$n>;
#[inline]
fn rem(self, rhs: R) -> Self::Output {
$crate::FlagSet::from(self) % rhs
}
}
$crate::flags! { $($next)* }
};
}