easybitflags/
lib.rs

1pub use flags_derive::derive_flags;
2use std::{
3    fmt::Debug,
4    marker::PhantomData,
5    ops::{BitAnd, BitOr, BitXor, Deref, Not, Shl, Shr},
6};
7
8/// A trait to define which primitives can be used as a primitive for a flags.
9/// Restricted to unsigned types for ease of use.
10pub trait FlagPrimitive:
11    Sized
12    + Not<Output = Self>
13    + BitAnd<Self, Output = Self>
14    + BitOr<Self, Output = Self>
15    + BitAnd<Self, Output = Self>
16    + BitXor<Self, Output = Self>
17    + Shl<Self, Output = Self>
18    + Shr<Self, Output = Self>
19    + Clone
20    + Copy
21    + Debug
22    + Eq
23{
24    /// <code>0</code> in this type
25    const ZERO: Self;
26    /// <code>1</code> in this type
27    const ONE: Self;
28}
29impl FlagPrimitive for u8 {
30    const ZERO: Self = 0;
31    const ONE: Self = 1;
32}
33impl FlagPrimitive for u16 {
34    const ZERO: Self = 0;
35    const ONE: Self = 1;
36}
37impl FlagPrimitive for u32 {
38    const ZERO: Self = 0;
39    const ONE: Self = 1;
40}
41impl FlagPrimitive for u64 {
42    const ZERO: Self = 0;
43    const ONE: Self = 1;
44}
45impl FlagPrimitive for u128 {
46    const ZERO: Self = 0;
47    const ONE: Self = 1;
48}
49impl FlagPrimitive for usize {
50    const ZERO: Self = 0;
51    const ONE: Self = 1;
52}
53/// Trait of the flag enum.
54pub trait FlagValue: Sized + Debug + Clone + Copy + AsRef<Self::Collection> {
55    /// The innertype in which this element is stored.
56    type Bits: FlagPrimitive;
57    /// Collection Type associated with Self
58    type Collection: FlagValueCollection<Self>;
59    /// MASK of all valid bits
60    const MASK: Self::Bits;
61    fn to_primitive(&self) -> Self::Bits;
62    fn from_primitive(value: &Self::Bits) -> Option<Self>;
63    fn all() -> Self::Collection {
64        Self::Collection::from_primitive(&Self::MASK)
65    }
66    fn contains<T: Into<Self::Collection>>(&self, needle: T) -> bool {
67        let needle: Self::Bits = needle.into().to_primitive();
68        let haystack: Self::Bits = self.to_primitive();
69        needle & haystack == needle
70    }
71}
72/// Trait of the flag collections
73pub trait FlagValueCollection<E: FlagValue>:
74    Sized + Deref<Target = E::Bits> + AsRef<E::Bits> + From<E>
75{
76    fn to_primitive(&self) -> E::Bits;
77    fn from_primitive(value: &E::Bits) -> Self;
78    fn into_iter(&self) -> FlagIterator<E::Bits, E, Self> {
79        FlagIterator::new(self.to_primitive())
80    }
81    fn len(&self) -> u32;
82    fn contains<T: Into<Self>>(&self, needle: T) -> bool {
83        let needle: E::Bits = needle.into().to_primitive();
84        let haystack: E::Bits = self.to_primitive();
85        needle & haystack == needle
86    }
87}
88pub struct FlagIterator<T: FlagPrimitive, V: FlagValue<Bits = T>, C: FlagValueCollection<V>> {
89    mask: T,
90    current_bit: T,
91    value: T,
92    phantom: PhantomData<V>,
93    collection: PhantomData<C>,
94}
95impl<T: FlagPrimitive, V: FlagValue<Bits = T>, C: FlagValueCollection<V>> FlagIterator<T, V, C> {
96    pub fn new(value: T) -> Self {
97        FlagIterator {
98            mask: V::MASK,
99            current_bit: T::ONE,
100            value,
101            phantom: PhantomData,
102            collection: PhantomData,
103        }
104    }
105}
106
107impl<T: FlagPrimitive, V: FlagValue<Bits = T>, C: FlagValueCollection<V>> Iterator
108    for FlagIterator<T, V, C>
109{
110    type Item = V;
111
112    fn next(&mut self) -> Option<Self::Item> {
113        if self.mask == T::ZERO {
114            return None;
115        }
116        while self.mask & self.current_bit == T::ZERO {
117            self.current_bit = self.current_bit << T::ONE;
118        }
119        self.mask = self.mask & !self.current_bit & self.value;
120        V::from_primitive(&self.current_bit)
121    }
122}
123
124#[cfg(test)]
125mod test {
126    use flags_derive::derive_flags;
127    derive_flags! {
128        #[derive(Debug)]
129        #[flag]
130        pub enum Flag {
131            A = 2,B = 4,C = 8,D = 16
132        }
133        #[flags]
134        pub struct Flags(u8);
135    }
136    #[test]
137    fn test() {
138        dbg!(Flag::A | Flag::B);
139    }
140}