#![no_std]
#![forbid(missing_docs)]
#![allow(clippy::missing_safety_doc)]
use core::borrow::Borrow;
use core::cmp::Ordering;
use core::fmt::{self, Debug};
use core::hash::{Hash, Hasher};
use core::iter::{FromIterator, Sum};
use core::marker::PhantomData;
use core::mem;
use core::ops::*;
#[doc(hidden)]
pub mod __internal;
use __internal::{WORD_BITS, WORD_MASK, WORD_SHIFT};
#[cfg(feature = "serde")]
use crate::__internal::serde;
pub unsafe trait BigEnumSetType: Copy + Eq + crate::__internal::BigEnumSetTypePrivate {}
#[derive(Copy, Clone, PartialEq, Eq)]
pub struct BigEnumSet<T: BigEnumSetType> {
#[doc(hidden)]
pub __repr: T::Repr,
}
impl<T: BigEnumSetType> BigEnumSet<T> {
fn has_bit(&self, bit: u16) -> bool {
let word_idx = bit >> WORD_SHIFT;
let bit_idx = bit & WORD_MASK;
let mask = 1usize << bit_idx;
self.__repr.as_ref()[usize::from(word_idx)] & mask == mask
}
fn set_bit(&mut self, bit: u16, val: bool) -> bool {
let word_idx = bit >> WORD_SHIFT;
let bit_idx = bit & WORD_MASK;
let mask = 1usize << bit_idx;
let word = &mut self.__repr.as_mut()[usize::from(word_idx)];
let old = *word & mask != 0;
if val {
*word |= mask;
} else {
*word &= !mask;
}
old
}
pub const EMPTY: BigEnumSet<T> = BigEnumSet { __repr: T::REPR_NONE };
pub fn new() -> Self {
Self::EMPTY
}
pub fn only(t: T) -> Self {
let mut set = Self::EMPTY;
set.set_bit(t.enum_into_u16(), true);
set
}
pub fn empty() -> Self {
Self::EMPTY
}
pub fn all() -> Self {
Self { __repr: T::REPR_ALL }
}
pub fn bit_width() -> u32 {
let len = T::REPR_LEN;
len as u32 * u32::from(WORD_BITS) - T::REPR_ALL.as_ref()[len - 1].leading_zeros()
}
pub fn variant_count() -> u32 {
T::REPR_ALL.as_ref().iter().map(|w| w.count_ones()).sum()
}
pub fn as_bits(&self) -> &[usize] {
self.__repr.as_ref()
}
pub fn try_from_bits(bits: &[usize]) -> Option<Self> {
let mut bits_valid = bits.iter()
.zip(T::REPR_ALL.as_ref().iter())
.all(|(w, all)| *w & !*all == 0);
if bits.len() > T::REPR_LEN {
bits_valid &= bits[T::REPR_LEN ..].iter().all(|w| *w == 0);
}
if !bits_valid {
return None;
}
let mut set = Self::new();
set.__repr.as_mut().iter_mut()
.zip(bits.iter())
.for_each(|(dst, src)| *dst = *src);
Some(set)
}
pub fn from_bits_truncated(bits: &[usize]) -> Self {
let all_set = T::REPR_ALL;
let masked_bits = bits.iter()
.zip(all_set.as_ref().iter())
.map(|(w, all)| *w & *all);
let mut set = Self::new();
set.__repr.as_mut().iter_mut()
.zip(masked_bits)
.for_each(|(dst, src)| *dst = src);
set
}
pub fn len(&self) -> usize {
self.__repr.as_ref().iter().map(|w| w.count_ones() as usize).sum()
}
pub fn is_empty(&self) -> bool {
self.__repr == T::REPR_NONE
}
pub fn clear(&mut self) {
self.__repr = T::REPR_NONE
}
fn check_all<F>(&self, other: &Self, f: F) -> bool
where F: Fn(usize, usize) -> bool {
self.__repr.as_ref().iter()
.zip(other.__repr.as_ref().iter())
.all(|(w1, w2)| f(*w1, *w2))
}
pub fn is_disjoint<O: Borrow<Self>>(&self, other: O) -> bool {
self.check_all(other.borrow(), |w1, w2| w1 & w2 == 0)
}
pub fn is_superset<O: Borrow<Self>>(&self, other: O) -> bool {
self.check_all(other.borrow(), |w1, w2| w1 & w2 == w2)
}
pub fn is_subset<O: Borrow<Self>>(&self, other: O) -> bool {
other.borrow().is_superset(self)
}
fn apply_op<F>(&mut self, other: &Self, op: F)
where F: Fn(usize, usize) -> usize {
self.__repr.as_mut().iter_mut()
.zip(other.__repr.as_ref().iter())
.for_each(|(w1, w2)| *w1 = op(*w1, *w2));
}
pub fn union<O: Borrow<Self>>(&self, other: O) -> Self {
let mut result = *self;
__internal::union(&mut result, other.borrow());
result
}
pub fn intersection<O: Borrow<Self>>(&self, other: O) -> Self {
let mut result = *self;
__internal::intersection(&mut result, other.borrow());
result
}
pub fn difference<O: Borrow<Self>>(&self, other: O) -> Self {
let mut result = *self;
__internal::difference(&mut result, other.borrow());
result
}
pub fn symmetrical_difference<O: Borrow<Self>>(&self, other: O) -> Self {
let mut result = *self;
__internal::symmetrical_difference(&mut result, other.borrow());
result
}
pub fn complement(&self) -> Self {
let mut result = *self;
__internal::complement(&mut result);
result
}
pub fn contains(&self, value: T) -> bool {
self.has_bit(value.enum_into_u16())
}
pub fn insert(&mut self, value: T) -> bool {
!self.set_bit(value.enum_into_u16(), true)
}
pub fn remove(&mut self, value: T) -> bool {
self.set_bit(value.enum_into_u16(), false)
}
pub fn insert_all<O: Borrow<Self>>(&mut self, other: O) {
__internal::union(self, other.borrow());
}
pub fn remove_all<O: Borrow<Self>>(&mut self, other: O) {
__internal::difference(self, other.borrow());
}
pub fn iter(&self) -> EnumSetIter<&BigEnumSet<T>, T> {
EnumSetIter(self, 0, PhantomData)
}
}
impl<T: BigEnumSetType> Default for BigEnumSet<T> {
fn default() -> Self {
Self::new()
}
}
impl<T: BigEnumSetType> IntoIterator for BigEnumSet<T> {
type Item = T;
type IntoIter = EnumSetIter<BigEnumSet<T>, T>;
fn into_iter(self) -> Self::IntoIter {
EnumSetIter(self, 0, PhantomData)
}
}
impl <T: BigEnumSetType> Sum for BigEnumSet<T> {
fn sum<I: Iterator<Item=Self>>(iter: I) -> Self {
let mut a = Self::empty();
for v in iter {
a |= v
}
a
}
}
impl <'a, T: 'a + BigEnumSetType> Sum<&'a BigEnumSet<T>> for BigEnumSet<T> {
fn sum<I: Iterator<Item=&'a Self>>(iter: I) -> Self {
let mut a = Self::empty();
for v in iter {
a |= *v
}
a
}
}
impl <T: BigEnumSetType> Sum<T> for BigEnumSet<T> {
fn sum<I: Iterator<Item=T>>(iter: I) -> Self {
let mut a = Self::empty();
for v in iter {
a |= v
}
a
}
}
impl <'a, T: 'a + BigEnumSetType> Sum<&'a T> for BigEnumSet<T> {
fn sum<I: Iterator<Item=&'a T>>(iter: I) -> Self {
let mut a = Self::empty();
for v in iter {
a |= *v
}
a
}
}
macro_rules! impl_op {
($op_trait:ident, $op_method:ident, $func:ident) => {
impl<T: BigEnumSetType> $op_trait<BigEnumSet<T>> for BigEnumSet<T> {
type Output = BigEnumSet<T>;
fn $op_method(mut self, other: BigEnumSet<T>) -> Self::Output {
__internal::$func(&mut self, &other);
self
}
}
impl<T: BigEnumSetType> $op_trait<BigEnumSet<T>> for &BigEnumSet<T> {
type Output = BigEnumSet<T>;
fn $op_method(self, other: BigEnumSet<T>) -> Self::Output {
let mut result = self.clone();
__internal::$func(&mut result, &other);
result
}
}
impl<T: BigEnumSetType> $op_trait<&BigEnumSet<T>> for BigEnumSet<T> {
type Output = BigEnumSet<T>;
fn $op_method(mut self, other: &BigEnumSet<T>) -> Self::Output {
__internal::$func(&mut self, other);
self
}
}
impl<T: BigEnumSetType> $op_trait<&BigEnumSet<T>> for &BigEnumSet<T> {
type Output = BigEnumSet<T>;
fn $op_method(self, other: &BigEnumSet<T>) -> Self::Output {
let mut result = self.clone();
__internal::$func(&mut result, other);
result
}
}
};
}
impl_op!(BitOr, bitor, union);
impl_op!(BitAnd, bitand, intersection);
impl_op!(Sub, sub, difference);
impl_op!(BitXor, bitxor, symmetrical_difference);
macro_rules! impl_op_enum {
($op_trait:ident, $op_method:ident, $func:ident) => {
impl<T: BigEnumSetType> $op_trait<T> for BigEnumSet<T> {
type Output = Self;
fn $op_method(mut self, value: T) -> Self::Output {
__internal::$func(&mut self, value);
self
}
}
impl<T: BigEnumSetType> $op_trait<T> for &BigEnumSet<T> {
type Output = BigEnumSet<T>;
fn $op_method(self, value: T) -> Self::Output {
let mut result = self.clone();
__internal::$func(&mut result, value);
result
}
}
};
}
impl_op_enum!(BitOr, bitor, union_enum);
impl_op_enum!(BitAnd, bitand, intersection_enum);
impl_op_enum!(Sub, sub, difference_enum);
impl_op_enum!(BitXor, bitxor, symmetrical_difference_enum);
macro_rules! impl_assign_op {
($op_trait:ident, $op_method:ident, $func:ident) => {
impl<T: BigEnumSetType> $op_trait<BigEnumSet<T>> for BigEnumSet<T> {
fn $op_method(&mut self, other: BigEnumSet<T>) {
__internal::$func(self, &other);
}
}
impl<T: BigEnumSetType> $op_trait<&BigEnumSet<T>> for BigEnumSet<T> {
fn $op_method(&mut self, other: &BigEnumSet<T>) {
__internal::$func(self, other);
}
}
};
}
impl_assign_op!(BitOrAssign, bitor_assign, union);
impl_assign_op!(BitAndAssign, bitand_assign, intersection);
impl_assign_op!(SubAssign, sub_assign, difference);
impl_assign_op!(BitXorAssign, bitxor_assign, symmetrical_difference);
macro_rules! impl_assign_op_enum {
($op_trait:ident, $op_method:ident, $func:ident) => {
impl<T: BigEnumSetType> $op_trait<T> for BigEnumSet<T> {
fn $op_method(&mut self, value: T) {
__internal::$func(self, value);
}
}
};
}
impl_assign_op_enum!(BitOrAssign, bitor_assign, union_enum);
impl_assign_op_enum!(BitAndAssign, bitand_assign, intersection_enum);
impl_assign_op_enum!(SubAssign, sub_assign, difference_enum);
impl_assign_op_enum!(BitXorAssign, bitxor_assign, symmetrical_difference_enum);
impl<T: BigEnumSetType> Not for BigEnumSet<T> {
type Output = Self;
fn not(mut self) -> Self::Output {
__internal::complement(&mut self);
self
}
}
impl<T: BigEnumSetType> Not for &BigEnumSet<T> {
type Output = BigEnumSet<T>;
fn not(self) -> Self::Output {
self.complement()
}
}
impl<T: BigEnumSetType> From<T> for BigEnumSet<T> {
fn from(t: T) -> Self {
BigEnumSet::only(t)
}
}
impl<T: BigEnumSetType> PartialEq<T> for BigEnumSet<T> {
fn eq(&self, other: &T) -> bool {
self == &Self::only(*other)
}
}
impl<T: BigEnumSetType + Debug> Debug for BigEnumSet<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut is_first = true;
f.write_str("BigEnumSet(")?;
for v in self.iter() {
if !is_first {
f.write_str(" | ")?;
}
is_first = false;
v.fmt(f)?;
}
f.write_str(")")?;
Ok(())
}
}
impl<T: BigEnumSetType> Hash for BigEnumSet<T> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.__repr.hash(state)
}
}
impl<T: BigEnumSetType> PartialOrd for BigEnumSet<T> {
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
self.__repr.partial_cmp(&other.__repr)
}
}
impl<T: BigEnumSetType> Ord for BigEnumSet<T> {
fn cmp(&self, other: &Self) -> Ordering {
self.__repr.cmp(&other.__repr)
}
}
#[cfg(feature = "serde")]
impl<T: BigEnumSetType> serde::Serialize for BigEnumSet<T> {
fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
T::serialize(self, serializer)
}
}
#[cfg(feature = "serde")]
impl<'de, T: BigEnumSetType> serde::Deserialize<'de> for BigEnumSet<T> {
fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
T::deserialize(deserializer)
}
}
#[derive(Clone, Debug)]
pub struct EnumSetIter<S, T>(S, u32, PhantomData<T>)
where
S: Borrow<BigEnumSet<T>>,
T: BigEnumSetType;
impl<S, T> Iterator for EnumSetIter<S, T>
where
S: Borrow<BigEnumSet<T>>,
T: BigEnumSetType,
{
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
let set = self.0.borrow();
while self.1 < BigEnumSet::<T>::bit_width() {
let bit = self.1 as u16;
self.1 += 1;
if set.has_bit(bit) {
return unsafe { Some(T::enum_from_u16(bit)) };
}
}
None
}
fn size_hint(&self) -> (usize, Option<usize>) {
let set = self.0.borrow();
let left_idx = (self.1 >> WORD_SHIFT) as usize;
let slice = &set.__repr.as_ref()[left_idx..];
let left = if slice.is_empty() {
0
} else {
let mask = !((1 << (self.1 & u32::from(WORD_MASK))) - 1);
let mut left = (slice[0] & mask).count_ones();
for w in &slice[1..] {
left += w.count_ones();
}
left as usize
};
(left, Some(left))
}
}
impl<S, T> ExactSizeIterator for EnumSetIter<S, T>
where
S: Borrow<BigEnumSet<T>>,
T: BigEnumSetType,
{
}
impl<T: BigEnumSetType> Extend<T> for BigEnumSet<T> {
fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
iter.into_iter().for_each(|v| {
self.insert(v);
});
}
}
impl<T: BigEnumSetType> FromIterator<T> for BigEnumSet<T> {
fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
let mut set = BigEnumSet::default();
set.extend(iter);
set
}
}
#[macro_export]
macro_rules! big_enum_set {
( $( $value:path )|* $( | )? ) => {{
let mut set = $crate::__internal::EnumSetSameTypeHack {
unified: &[ $( $value ),* ],
set: $crate::BigEnumSet::EMPTY,
}.set;
$(
let bit = $value as u16;
set.__repr[(bit >> $crate::__internal::WORD_SHIFT) as usize] |= 1 << (bit & $crate::__internal::WORD_MASK);
)*
set
}};
}
pub use big_enum_set_derive::BigEnumSetType;