use crate::*;
pub trait BitMasksExtension : IntegerUnsigned
{
#[must_use]
fn masked (self, mask : Self, set : bool) -> Self { if set { self.masked_set_one(mask) } else { self.masked_set_zero(mask) } }
#[must_use]
fn masked_set_one (self, mask : Self) -> Self { self | mask }
#[must_use]
fn masked_set_zero (self, mask : Self) -> Self { self & !mask }
#[must_use]
fn masked_toggle (self, mask : Self) -> Self { self ^ mask }
fn mask (&mut self, mask : Self, set : bool) -> &mut Self { *self = self.masked(mask, set); self }
fn mask_set_one (&mut self, mask : Self) -> &mut Self { *self = self.masked_set_one(mask); self }
fn mask_set_zero (&mut self, mask : Self) -> &mut Self { *self = self.masked_set_zero(mask); self }
fn mask_toggle (&mut self, mask : Self) -> &mut Self { *self = self.masked_toggle(mask); self }
fn mask_all_true (&self, mask : Self) -> bool { let m = mask; (*self & m) == m }
fn mask_any_one (&self, mask : Self) -> bool { (*self & mask).is_non_zero() }
fn mask_any_zero (&self, mask : Self) -> bool { !self.mask_any_one(mask) }
}
impl<T> BitMasksExtension for T where T : IntegerUnsigned { }
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy
{
flags : U,
phantom : PhantomData<F>,
}
impl<F,U> Debug for BitFlags<F,U>
where
U : IntegerUnsigned + From<F>, F : MaxValue + Copy,
F : TryFrom<U> + Debug,
RangeInclusive<U>: Iterator<Item = U>,
{
fn fmt(&self, f: &mut Formatter<'_>) -> DResult
{
let mut it = self.into_iter().peekable();
write!(f, "[")?;
while let Some(v) = it.next()
{
write!(f, "{:?}", v)?;
if it.peek().is_some()
{
write!(f, ", ")?;
}
}
write!(f, "]")
}
}
impl<F,U> From<F> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy
{
fn from(value: F) -> Self { Self::from_flag(value) }
}
impl<F,U> Zero for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy
{
const ZERO : Self = unsafe { Self::from_flags_uncheck(U::ZERO) };
}
impl<F,U> BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy
{
pub const unsafe fn from_flags_uncheck(flags : U) -> Self { Self { flags, phantom: PhantomData }}
pub fn from_flags(flags : U) -> Self { let max : U = U::ONE << F::MAX.into(); unsafe { Self::from_flags_uncheck(flags & (max | max - U::ONE)) } }
pub fn from_flag(flag : F) -> Self { Self::from_flags(U::ONE << flag.into()) }
pub fn new() -> Self { Self::ZERO }
pub fn flags(self) -> U { self.flags }
}
impl<F,U> BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy
{
#[must_use]
pub fn with (mut self, flag : F, set : bool) -> Self { self.set(flag, set); self }
#[must_use]
pub fn added (mut self, flag : F) -> Self { self.add(flag); self }
#[must_use]
pub fn removed(mut self, flag : F) -> Self { self.remove(flag); self }
#[must_use]
pub fn toggled(mut self, flag : F) -> Self { self.toggle(flag); self }
pub fn set (&mut self, flag : F, set : bool) -> &mut Self { self.flags.mask(U::ONE << flag.into(),set); self }
pub fn add (&mut self, flag : F) -> &mut Self { self.flags.mask_set_one(U::ONE << flag.into()); self }
pub fn remove(&mut self, flag : F) -> &mut Self { self.flags.mask_set_zero(U::ONE << flag.into()); self }
pub fn toggle(&mut self, flag : F) -> &mut Self { self.flags.mask_toggle(U::ONE << flag.into()); self }
pub fn have(&self, flag : F) -> bool { self.flags.mask_any_one(U::ONE << flag.into()) }
pub fn have_any(&self, flags : &[F]) -> bool { flags.iter().any(|f| self.have(*f)) }
pub fn have_all(&self, flags : &[F]) -> bool { flags.iter().all(|f| self.have(*f)) }
}
impl<F,U> IntoIterator for BitFlags<F,U>
where
U : IntegerUnsigned + From<F>,
F : MaxValue + Copy,
F : TryFrom<U>, RangeInclusive<U>: Iterator<Item = U>
{
type Item=F;
type IntoIter=BitFlagsIntoIter<F,U>;
fn into_iter(self) -> Self::IntoIter { BitFlagsIntoIter::new(self) }
}
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct BitFlagsIntoIter<F,U>
where
U : IntegerUnsigned + From<F>,
F : MaxValue + Copy + TryFrom<U>,
RangeInclusive<U>: Iterator<Item = U>
{
bitflag : BitFlags<F,U>,
flag_idx : U,
}
impl<F,U> BitFlagsIntoIter<F,U>
where
U : IntegerUnsigned + From<F>,
F : MaxValue + Copy + TryFrom<U>,
RangeInclusive<U>: Iterator<Item = U>
{
pub fn new_start_at(bitflag : BitFlags<F,U>, idx : U) -> Self { Self { flag_idx: idx, bitflag }}
pub fn new(bitflag : BitFlags<F,U>) -> Self { Self::new_start_at(bitflag, U::ZERO) }
}
impl<F,U> Iterator for BitFlagsIntoIter<F,U>
where
U : IntegerUnsigned + From<F>,
F : MaxValue + Copy + TryFrom<U>,
RangeInclusive<U>: Iterator<Item = U>
{
type Item=F;
fn next(&mut self) -> Option<Self::Item>
{
debug_assert!(U::from(F::MAX) != U::MAX); loop
{
if self.bitflag.flags.mask_any_one(U::ONE << self.flag_idx)
{
if let Ok(v) = F::try_from(self.flag_idx)
{
self.flag_idx += U::ONE;
return Some(v);
}
}
self.flag_idx += U::ONE;
if self.flag_idx > F::MAX.into()
{
return None;
}
}
}
}
impl<F,U> BitAnd<Self> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy { type Output=Self; fn bitand(self, rhs: Self) -> Self::Output { Self::from_flags(self.flags.bitand(rhs.flags)) } }
impl<F,U> BitAndAssign<Self> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy { fn bitand_assign(&mut self, rhs: Self) { self.flags.bitand_assign(rhs.flags); } }
impl<F,U> BitAnd<F> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy { type Output=Self; fn bitand(self, rhs: F) -> Self::Output { self.bitand(Self::from(rhs)) } }
impl<F,U> BitAndAssign<F> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy { fn bitand_assign(&mut self, rhs: F) { self.bitand_assign(Self::from(rhs)); } }
impl<F,U> BitOr<Self> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy { type Output=Self; fn bitor(self, rhs: Self) -> Self::Output { Self::from_flags(self.flags.bitor(rhs.flags)) } }
impl<F,U> BitOrAssign<Self> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy { fn bitor_assign(&mut self, rhs: Self) { self.flags.bitor_assign(rhs.flags); } }
impl<F,U> BitOr<F> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy { type Output=Self; fn bitor(self, rhs: F) -> Self::Output { self.bitor(Self::from(rhs)) } }
impl<F,U> BitOrAssign<F> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy { fn bitor_assign(&mut self, rhs: F) { self.bitor_assign(Self::from(rhs)); } }
impl<F,U> BitXor<Self> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy { type Output=Self; fn bitxor(self, rhs: Self) -> Self::Output { Self::from_flags(self.flags.bitxor(rhs.flags)) } }
impl<F,U> BitXorAssign<Self> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy { fn bitxor_assign(&mut self, rhs: Self) { self.flags.bitxor_assign(rhs.flags); } }
impl<F,U> BitXor<F> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy { type Output=Self; fn bitxor(self, rhs: F) -> Self::Output { self.bitxor(Self::from(rhs)) } }
impl<F,U> BitXorAssign<F> for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy { fn bitxor_assign(&mut self, rhs: F) { self.bitxor_assign(Self::from(rhs)); } }
impl<F,U> Not for BitFlags<F,U> where U : IntegerUnsigned + From<F>, F : MaxValue + Copy
{
type Output=Self;
fn not(self) -> Self::Output { Self::from_flags(!self.flags) }
}
#[cfg(test)]
mod big_flag_ex
{
use super::*;
type Team = BitFlags<TeamFlag, u8>;
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq, Debug)]
enum TeamFlag
{
Blue,
Red,
Yellow,
}
impl MaxValue for TeamFlag
{
const MAX : Self = Self::Yellow;
}
impl From<TeamFlag> for u8
{
fn from(value: TeamFlag) -> Self {
value as u8
}
}
impl TryFrom<u8> for TeamFlag
{
type Error=();
fn try_from(value: u8) -> Result<Self, Self::Error> {
Ok
(
match value
{
0 => TeamFlag::Blue,
1 => TeamFlag::Red,
2 => TeamFlag::Yellow,
_ => return Err(())
}
)
}
}
#[test]
fn old_version()
{
}
#[test]
fn new_version()
{
let mut t1 = Team::ZERO.added(TeamFlag::Blue).added(TeamFlag::Red);
assert!(t1.have(TeamFlag::Blue));
assert!(t1.have(TeamFlag::Red));
assert!(t1.have(TeamFlag::Yellow).not());
t1.toggle(TeamFlag::Blue);
assert!(t1.have(TeamFlag::Blue).not());
}
#[test]
fn new_version_some_op()
{
let mut t1 = Team::ZERO | TeamFlag::Blue | TeamFlag::Red;
t1 ^= TeamFlag::Red;
assert!(t1.have(TeamFlag::Blue));
assert!(t1.have(TeamFlag::Red).not());
assert!(t1.have(TeamFlag::Yellow).not());
t1 |= TeamFlag::Yellow;
assert!(t1.have(TeamFlag::Yellow));
}
#[test]
fn rep()
{
let t1 = Team::ZERO | TeamFlag::Blue | TeamFlag::Red;
assert_eq!(t1.flags(), 0b0000_0011);
let t1 = !t1;
assert_eq!(t1.flags(), 0b0000_0100); }
#[test]
fn iteration()
{
let mut t1 = Team::new(); let blue_and_yellow = [TeamFlag::Blue, TeamFlag::Yellow];
for flag in blue_and_yellow
{
t1 |= flag;
}
assert!(t1.have_all(&blue_and_yellow));
assert!(t1.have(TeamFlag::Red).not());
assert_eq!(t1.into_iter().count(), blue_and_yellow.len());
for (f1, f2) in t1.into_iter().zip(blue_and_yellow.iter().copied())
{
assert_eq!(f1, f2);
}
}
}