#![deny(missing_docs)]
extern crate enum_like;
extern crate bit_set;
use enum_like::EnumLike;
use bit_set::BitSet;
use std::marker::PhantomData;
use std::iter::FromIterator;
use std::fmt;
#[derive(Clone, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub struct EnumSet<E: EnumLike> {
inner: BitSet,
_phantom: PhantomData<E>,
}
impl<E: EnumLike> EnumSet<E> {
pub fn into_bit_set(self) -> BitSet {
self.inner
}
pub fn get_ref(&self) -> &BitSet {
&self.inner
}
pub fn from_bit_set(inner: BitSet) -> Self {
Self {
inner,
_phantom: PhantomData,
}
}
pub fn new() -> Self {
Self {
inner: BitSet::new(),
_phantom: PhantomData,
}
}
pub fn shrink_to_fit(&mut self) {
self.inner.shrink_to_fit()
}
pub fn iter(&self) -> WrapIter<E, bit_set::Iter<'_, u32>> {
WrapIter::<E, _>::new(self.inner.iter())
}
pub fn union<'a>(&'a self, other: &'a Self) -> Union<'a, E> {
WrapIter::<E, _>::new(self.inner.union(&other.inner))
}
pub fn intersection<'a>(&'a self, other: &'a Self) -> Intersection<'a, E> {
WrapIter::<E, _>::new(self.inner.intersection(&other.inner))
}
pub fn difference<'a>(&'a self, other: &'a Self) -> Difference<'a, E> {
WrapIter::<E, _>::new(self.inner.difference(&other.inner))
}
pub fn symmetric_difference<'a>(&'a self, other: &'a Self) -> SymmetricDifference<'a, E> {
WrapIter::<E, _>::new(self.inner.symmetric_difference(&other.inner))
}
pub fn union_with(&mut self, other: &Self) {
self.inner.union_with(&other.inner)
}
pub fn intersect_with(&mut self, other: &Self) {
self.inner.intersect_with(&other.inner)
}
pub fn difference_with(&mut self, other: &Self) {
self.inner.difference_with(&other.inner)
}
pub fn symmetric_difference_with(&mut self, other: &Self) {
self.inner.symmetric_difference_with(&other.inner)
}
pub fn len(&self) -> usize {
self.inner.len()
}
pub fn is_empty(&self) -> bool {
self.inner.is_empty()
}
pub fn clear(&mut self) {
self.inner.clear()
}
pub fn contains(&self, value: E) -> bool {
let d = value.to_discr();
self.inner.contains(d)
}
pub fn is_disjoint(&self, other: &Self) -> bool {
self.inner.is_disjoint(&other.inner)
}
pub fn is_subset(&self, other: &Self) -> bool {
self.inner.is_subset(&other.inner)
}
pub fn is_superset(&self, other: &Self) -> bool {
self.inner.is_superset(&other.inner)
}
pub fn insert(&mut self, value: E) -> bool {
let d = value.to_discr();
self.inner.insert(d)
}
pub fn remove(&mut self, value: E) -> bool {
let d = value.to_discr();
self.inner.remove(d)
}
}
impl<E: EnumLike> Default for EnumSet<E> {
fn default() -> Self {
Self::new()
}
}
impl<E: EnumLike> FromIterator<E> for EnumSet<E> {
fn from_iter<I: IntoIterator<Item = E>>(iter: I) -> Self {
let mut ret = Self::default();
ret.extend(iter);
ret
}
}
impl<E: EnumLike> Extend<E> for EnumSet<E> {
fn extend<I: IntoIterator<Item = E>>(&mut self, iter: I) {
for i in iter {
self.insert(i);
}
}
}
impl<E: EnumLike + fmt::Debug> fmt::Debug for EnumSet<E> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_set().entries(self.iter()).finish()
}
}
#[derive(Debug)]
pub struct WrapIter<E: EnumLike, I: Iterator<Item=usize>> {
inner: I,
_phantom: PhantomData<E>,
}
pub type Iter<'a, E> = WrapIter<E, bit_set::Iter<'a, u32>>;
pub type Union<'a, E> = WrapIter<E, bit_set::Union<'a, u32>>;
pub type Intersection<'a, E> = WrapIter<E, bit_set::Intersection<'a, u32>>;
pub type Difference<'a, E> = WrapIter<E, bit_set::Difference<'a, u32>>;
pub type SymmetricDifference<'a, E> = WrapIter<E, bit_set::SymmetricDifference<'a, u32>>;
impl<E: EnumLike, I: Iterator<Item=usize>> WrapIter<E, I> {
fn new(inner: I) -> Self {
Self { inner, _phantom: PhantomData }
}
}
impl<E: EnumLike, I: Iterator<Item=usize>> Iterator for WrapIter<E, I> {
type Item = E;
fn next(&mut self) -> Option<E> {
self.inner.next().map(|x| E::from_discr(x))
}
fn size_hint(&self) -> (usize, Option<usize>) {
self.inner.size_hint()
}
}
impl<'a, E: EnumLike> IntoIterator for &'a EnumSet<E> {
type Item = E;
type IntoIter = WrapIter<E, bit_set::Iter<'a, u32>>;
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
enum ABC {
A,
B,
C,
}
unsafe impl EnumLike for ABC {
const NUM_VARIANTS: usize = 3;
fn to_discr(self) -> usize {
match self {
ABC::A => 0,
ABC::B => 1,
ABC::C => 2,
}
}
fn from_discr(x: usize) -> Self {
match x {
0 => ABC::A,
1 => ABC::B,
2 => ABC::C,
_ => panic!("Enum ABC has no variant {}", x),
}
}
}
#[test]
fn create() {
let mut e = EnumSet::new();
assert_eq!(e.contains(ABC::A), false);
assert_eq!(e.insert(ABC::A), true);
assert_eq!(e.insert(ABC::A), false);
assert_eq!(e.contains(ABC::A), true);
assert_eq!(e.remove(ABC::A), true);
assert_eq!(e.remove(ABC::A), false);
assert_eq!(e.contains(ABC::A), false);
}
}