use std::{borrow::Borrow, iter::Sum, ops::*};
pub use crate::bit_enum;
use crate::prelude::*;
pub trait BitOperational:
Clone
+ Eq
+ for<'a> BitAnd<&'a Self, Output = Self>
+ for<'a> BitOr<&'a Self, Output = Self>
+ Not<Output = Self>
+ Default
{
}
impl<
T: Clone
+ Eq
+ for<'a> BitAnd<&'a Self, Output = Self>
+ for<'a> BitOr<&'a Self, Output = Self>
+ Not<Output = Self>
+ Default,
> BitOperational for T
{
}
#[derive(Default, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(transparent)]
pub struct Bits<T>(pub T);
impl<T: BitOperational> Bits<T> {
#[inline(always)]
pub fn has(self, bits: impl Borrow<T>) -> bool {
&(self & bits.borrow()).0 == bits.borrow()
}
#[inline(always)]
pub fn has_all<U: Borrow<T>, I: IntoIterator<Item = U>>(self, bits: I) -> bool {
self.has(bits.into_iter().sum::<Self>())
}
#[inline(always)]
pub fn zero() -> Self {
Default::default()
}
#[inline(always)]
pub fn into_iter<E: BitEnumeration<T>>(self) -> impl Iterator<Item = E> where T: Copy, E::Index: Into<usize> + TryFrom<usize> {
E::try_iter().filter(move |&e| self.has(e))
}
#[inline(always)]
pub fn iter<'a, E: BitEnumeration<T>>(&'a self) -> impl Iterator<Item = E> + 'a where T: Clone, E::Index: Into<usize> + TryFrom<usize> {
E::try_iter().filter(|&e| self.clone().has(e))
}
}
impl<T: BitOperational> Borrow<T> for Bits<T> {
#[inline(always)]
fn borrow(&self) -> &T {
&self.0
}
}
impl<'a, T: BitOperational> Borrow<T> for &'a Bits<T> {
#[inline(always)]
fn borrow(&self) -> &T {
&self.0
}
}
impl<T: BitOperational, U: Borrow<T>> Add<U> for Bits<T> {
type Output = Self;
#[inline(always)]
fn add(self, rhs: U) -> Self {
self | rhs
}
}
impl<T: BitOperational, U: Borrow<T>> AddAssign<U> for Bits<T> {
#[inline(always)]
fn add_assign(&mut self, rhs: U) {
*self = self.clone() + rhs;
}
}
impl<T: BitOperational, U: Borrow<T>> Sub<U> for Bits<T> {
type Output = Self;
#[inline(always)]
fn sub(self, rhs: U) -> Self {
self & -Bits(rhs.borrow().clone())
}
}
impl<T: BitOperational, U: Borrow<T>> SubAssign<U> for Bits<T> {
#[inline(always)]
fn sub_assign(&mut self, rhs: U) {
*self = self.clone() - rhs;
}
}
impl<T: BitOperational> Not for Bits<T> {
type Output = Self;
#[inline(always)]
fn not(self) -> Self::Output {
Bits(!self.0)
}
}
impl<T: BitOperational> Neg for Bits<T> {
type Output = Self;
#[inline(always)]
fn neg(self) -> Self::Output {
!self
}
}
impl<T: BitOperational, U: Borrow<T>> BitAnd<U> for Bits<T> {
type Output = Self;
#[inline(always)]
fn bitand(self, rhs: U) -> Self::Output {
Bits(self.0 & rhs.borrow())
}
}
impl<T: BitOperational, U: Borrow<T>> BitAndAssign<U> for Bits<T> {
#[inline(always)]
fn bitand_assign(&mut self, rhs: U) {
*self = self.clone() & rhs;
}
}
impl<T: BitOperational, U: Borrow<T>> BitOr<U> for Bits<T> {
type Output = Self;
#[inline(always)]
fn bitor(self, rhs: U) -> Self::Output {
Bits(self.0 | rhs.borrow())
}
}
impl<T: BitOperational, U: Borrow<T>> BitOrAssign<U> for Bits<T> {
#[inline(always)]
fn bitor_assign(&mut self, rhs: U) {
*self = self.clone() | rhs;
}
}
impl<T: BitOperational + for<'a> BitXor<&'a T, Output = T>, U: Borrow<T>> BitXor<U> for Bits<T> {
type Output = Self;
#[inline(always)]
fn bitxor(self, rhs: U) -> Self::Output {
Bits(self.0 ^ rhs.borrow())
}
}
impl<T: BitOperational + for<'a> BitXor<&'a T, Output = T>, U: Borrow<T>> BitXorAssign<U>
for Bits<T>
{
#[inline(always)]
fn bitxor_assign(&mut self, rhs: U) {
*self = self.clone() ^ rhs;
}
}
impl<T: BitOperational, U: Borrow<T>> Sum<U> for Bits<T> {
#[inline(always)]
fn sum<I: Iterator<Item = U>>(iter: I) -> Self {
Bits(iter.fold(T::default(), |t, u| t | u.borrow()))
}
}
impl<T: BitOperational, U: Borrow<T>> FromIterator<U> for Bits<T> {
#[inline(always)]
fn from_iter<I: IntoIterator<Item = U>>(iter: I) -> Self {
iter.into_iter().sum()
}
}
pub trait BitEnumeration<T: BitOperational + Clone>:
Enumeration<AssociatedValueType = Bits<T>> + Borrow<T>
{
#[inline(always)]
fn bit(&self) -> Bits<T> {
self.value_clone()
}
#[inline(always)]
fn zero_bit() -> Bits<T> {
Bits::zero()
}
#[inline(always)]
fn all_bits() -> Bits<T>
where
Self::Index: Into<usize> + TryFrom<usize>,
{
Self::try_iter().sum()
}
#[inline(always)]
fn from_bit(bit: T) -> Option<Self> where Self: FromValue {
Self::from_value(&Bits(bit)).ok()
}
#[inline(always)]
fn from_bit_unchecked(bit: T) -> Self where Self: FromValue {
Self::from_value_unchecked(&Bits(bit))
}
}
impl<T: BitOperational + Clone, E: Enumeration<AssociatedValueType = Bits<T>> + Borrow<T>> BitEnumeration<T> for E {}
#[macro_export]
macro_rules! bit_enum {
($(#[$enum_attr:meta])* $visibility:vis enum $name:ident ($t:ident; $associated_value_type:ty) $($(#[$attr:meta])* $variant:ident $(,)? $(;)?)*) => {
$crate::bit_enum!($(#[$enum_attr])* $visibility $name ($t; $associated_value_type) $($(#[$attr])* $variant)*);
};
($(#[$enum_attr:meta])* $visibility:vis $name:ident ($t:ident; $associated_value_type:ty) $($(#[$attr:meta])* $variant:ident $(,)? $(;)?)*) => {
$crate::enumerate!($(#[$enum_attr])* $visibility $name ($t; $crate::bitmask::Bits<$associated_value_type>) $($(#[$attr])* $variant = $crate::bitmask::Bits(1u8 as $associated_value_type << unsafe { ::std::mem::transmute::<$name, $t>($name::$variant) }))*);
impl ::std::borrow::Borrow<$associated_value_type> for $name {
#[inline(always)]
fn borrow(&self) -> &$associated_value_type {
use $crate::enumeration::Enumeration;
&self.value().0
}
}
impl<'a> ::std::borrow::Borrow<$associated_value_type> for &'a $name {
#[inline(always)]
fn borrow(&self) -> &$associated_value_type {
use $crate::enumeration::Enumeration;
&self.value().0
}
}
impl<T: ::std::borrow::Borrow<$associated_value_type>> ::std::ops::Add<T> for $name {
type Output = $crate::bitmask::Bits<$associated_value_type>;
#[inline(always)]
fn add(self, o: T) -> Self::Output {
use $crate::enumeration::Enumeration;
self.value_clone() + o
}
}
};
}