Skip to main content

enumset/
impl_set_mixed.rs

1use crate::repr::EnumSetTypeRepr;
2use crate::traits::{EnumSetType, EnumSetTypePrivate};
3use crate::{EnumSet, EnumSetTypeWithRepr};
4use core::cmp::Ordering;
5use core::fmt::{Debug, Display, Formatter};
6use core::hash::{Hash, Hasher};
7use core::iter::Sum;
8use core::ops::{
9    BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not, Sub, SubAssign,
10};
11
12#[cfg(feature = "serde")]
13use serde::{Deserialize, Serialize};
14
15/// Used to return potentially invalid variants of a [`MixedEnumSet`].
16#[derive(Copy, Clone, Ord, PartialOrd, Eq, PartialEq, Hash)]
17pub enum MixedValue<T: EnumSetType> {
18    /// A bit that is valid for the enum type.
19    Valid(T),
20    /// A bit that does not correspond to any variant of the enum.
21    Invalid(u32),
22}
23impl<T: EnumSetType> MixedValue<T> {
24    fn from_bit(b: u32) -> MixedValue<T> {
25        if T::ALL_BITS.has_bit(b) {
26            unsafe { MixedValue::Valid(T::enum_from_u32(b)) }
27        } else {
28            MixedValue::Invalid(b)
29        }
30    }
31}
32impl<T: EnumSetType> Debug for MixedValue<T>
33where T: Debug
34{
35    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
36        match self {
37            MixedValue::Valid(v) => v.fmt(f),
38            MixedValue::Invalid(b) => write!(f, "[{b}]"),
39        }
40    }
41}
42impl<T: EnumSetType> Display for MixedValue<T>
43where T: Display
44{
45    fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
46        match self {
47            MixedValue::Valid(v) => v.fmt(f),
48            MixedValue::Invalid(b) => write!(f, "[{b}]"),
49        }
50    }
51}
52#[cfg(feature = "defmt")]
53impl<T: EnumSetType + defmt::Format> defmt::Format for MixedValue<T> {
54    fn format(&self, f: defmt::Formatter) {
55        match self {
56            MixedValue::Valid(v) => defmt::write!(f, "{}", v),
57            MixedValue::Invalid(b) => defmt::write!(f, "[{}]", b),
58        }
59    }
60}
61
62/// A variant of [`EnumSet`] that preserves unknown bits.
63///
64/// It only works for enums with an
65/// [`#[enumset(repr = "…")]`](derive@crate::EnumSetType#representation-options) attribute used
66/// with a primitive integer type.
67///
68/// # Numeric Representation
69///
70/// `MixedEnumSet` uses the same underlying
71/// [`numeric representation`](EnumSet#numeric-representation) as `EnumSet`. However, bits that do
72/// not correspond to an enum variant can be set.
73///
74/// # Serialization
75///
76/// When the `serde` feature is enabled, `MixedEnumSet`s can be serialized and deserialized using
77/// the `serde` crate. It is always serialized as a single integer of the underlying repr type.
78///
79/// Unlike `EnumSet`, it ignores all flags given to [`EnumSetType`](derive@crate::EnumSetType).
80///
81/// # FFI Safety
82///
83/// `MixedEnumSet` may be used interchangeably with the specified repr type in FFI.
84#[derive(Copy, Clone, PartialEq, Eq)]
85#[repr(transparent)]
86pub struct MixedEnumSet<T: EnumSetTypeWithRepr> {
87    pub(crate) repr: <T as EnumSetTypePrivate>::Repr,
88}
89
90//region MixedEnumSet operations
91impl<T: EnumSetTypeWithRepr> MixedEnumSet<T> {
92    const EMPTY_REPR: Self = MixedEnumSet { repr: <T as EnumSetTypePrivate>::Repr::EMPTY };
93    const ALL_REPR: Self = MixedEnumSet { repr: T::ALL_BITS };
94
95    /// Creates an empty `MixedEnumSet`.
96    #[inline(always)]
97    pub const fn new() -> Self {
98        Self::EMPTY_REPR
99    }
100
101    /// Creates an empty `MixedEnumSet`.
102    ///
103    /// This is an alias for [`MixedEnumSet::new`].
104    #[inline(always)]
105    pub const fn empty() -> Self {
106        Self::EMPTY_REPR
107    }
108
109    /// Returns a `MixedEnumSet` containing all valid variants of the enum.
110    #[inline(always)]
111    pub const fn all() -> Self {
112        Self::ALL_REPR
113    }
114
115    /// The number of valid variants that this type can contain.
116    #[inline(always)]
117    pub const fn variant_count() -> u32 {
118        T::VARIANT_COUNT
119    }
120
121    set_common_methods!(T, <T as EnumSetTypePrivate>::Repr, impl Into<Self>);
122
123    /// Returns a set containing all enum variants not in this set.
124    ///
125    /// This method clears any unknown bits already existing in the set.
126    #[inline(always)]
127    pub fn complement(&self) -> Self {
128        Self { repr: !self.repr & T::ALL_BITS }
129    }
130
131    /// Returns a set containing all bits not in this set.
132    ///
133    /// This method sets any unknown bits not already existing in the set.
134    #[inline(always)]
135    pub fn full_complement(&self) -> Self {
136        Self { repr: !self.repr }
137    }
138
139    /// Returns the number of elements in this set, excluding unknown bits.
140    #[inline(always)]
141    pub fn valid_len(&self) -> usize {
142        (self.repr & T::ALL_BITS).count_ones() as usize
143    }
144
145    /// Returns whether this bitset contains any bits that do not correspond to a valid variant.
146    #[inline(always)]
147    pub fn has_unknown_bits(&self) -> bool {
148        !(self.repr & !T::ALL_BITS).is_empty()
149    }
150
151    /// Checks whether this set contains a specific bit.
152    #[inline(always)]
153    pub fn has_bit(&self, value: u32) -> bool {
154        self.repr.has_bit(value)
155    }
156
157    /// Adds a specific bit to this set.
158    ///
159    /// If the set did not have this bit present, `true` is returned.
160    ///
161    /// If the set did have this bit present, `false` is returned.
162    #[inline(always)]
163    pub fn insert_bit(&mut self, value: u32) -> bool {
164        let contains = !self.has_bit(value);
165        self.repr.add_bit(value);
166        contains
167    }
168
169    /// Removes a specific bit from this set. Returns whether the bit was present in the set.
170    #[inline(always)]
171    pub fn remove_bit(&mut self, value: u32) -> bool {
172        let contains = self.has_bit(value);
173        self.repr.remove_bit(value);
174        contains
175    }
176
177    /// Adds all elements in another set to this one.
178    #[inline(always)]
179    pub fn insert_all(&mut self, other: impl Into<Self>) {
180        self.repr = self.repr | other.into().repr
181    }
182
183    /// Removes all values in another set from this one.
184    #[inline(always)]
185    pub fn remove_all(&mut self, other: impl Into<Self>) {
186        self.repr = self.repr.and_not(other.into().repr);
187    }
188}
189
190set_common_impls!(MixedEnumSet, EnumSetTypeWithRepr);
191
192impl<T: EnumSetTypeWithRepr> PartialEq<MixedEnumSet<T>> for EnumSet<T> {
193    fn eq(&self, other: &MixedEnumSet<T>) -> bool {
194        self.repr == other.repr
195    }
196}
197impl<T: EnumSetTypeWithRepr> PartialEq<EnumSet<T>> for MixedEnumSet<T> {
198    fn eq(&self, other: &EnumSet<T>) -> bool {
199        self.repr == other.repr
200    }
201}
202
203#[cfg(feature = "defmt")]
204impl<T: EnumSetTypeWithRepr + defmt::Format> defmt::Format for MixedEnumSet<T> {
205    fn format(&self, f: defmt::Formatter) {
206        let mut i = self.iter();
207        if let Some(v) = i.next() {
208            defmt::write!(f, "{}", v);
209            for v in i {
210                defmt::write!(f, " | {}", v);
211            }
212        }
213    }
214}
215
216#[cfg(feature = "serde")]
217impl<T: EnumSetTypeWithRepr> Serialize for MixedEnumSet<T>
218where <T as EnumSetTypeWithRepr>::Repr: Serialize
219{
220    fn serialize<S: serde::Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
221        self.repr.serialize(serializer)
222    }
223}
224
225#[cfg(feature = "serde")]
226impl<'de, T: EnumSetTypeWithRepr> Deserialize<'de> for MixedEnumSet<T>
227where <T as EnumSetTypeWithRepr>::Repr: Deserialize<'de>
228{
229    fn deserialize<D: serde::Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
230        <T as EnumSetTypeWithRepr>::Repr::deserialize(deserializer).map(|x| Self { repr: x })
231    }
232}
233//endregion
234
235//region MixedEnumSet conversions
236impl<T: EnumSetTypeWithRepr> MixedEnumSet<T> {
237    /// Returns a `T::Repr` representing the elements of this set.
238    ///
239    /// Unlike the other `as_*` methods, this method is zero-cost and guaranteed not to fail,
240    /// panic or truncate any bits.
241    #[inline(always)]
242    pub const fn as_repr(&self) -> <T as EnumSetTypeWithRepr>::Repr {
243        self.repr
244    }
245
246    /// Constructs a bitset from a `T::Repr`.
247    #[inline(always)]
248    pub fn from_repr(bits: <T as EnumSetTypeWithRepr>::Repr) -> Self {
249        Self { repr: bits }
250    }
251
252    /// Constructs a bitset from a `T::Repr`, ignoring invalid variants.
253    #[inline(always)]
254    pub fn from_repr_truncated(bits: <T as EnumSetTypeWithRepr>::Repr) -> Self {
255        let mask = Self::all().as_repr();
256        let bits = bits & mask;
257        MixedEnumSet { repr: bits }
258    }
259
260    /// Converts this set into the corresponding [`EnumSet`].
261    ///
262    /// If any unknown bits are present in the set, this method will panic.
263    pub fn as_enumset(&self) -> EnumSet<T> {
264        self.try_as_enumset()
265            .expect("Bitset contains invalid variants.")
266    }
267
268    /// Attempts to convert this set into the corresponding [`EnumSet`].
269    ///
270    /// If any unknown bits are present in the set, this method will return `None`.
271    pub fn try_as_enumset(&self) -> Option<EnumSet<T>> {
272        if self.has_unknown_bits() {
273            None
274        } else {
275            Some(EnumSet { repr: self.repr })
276        }
277    }
278
279    /// Converts this set into the corresponding [`EnumSet`], ignoring bits that do not correspond
280    /// to a variant.
281    pub fn as_enumset_truncate(&self) -> EnumSet<T> {
282        EnumSet { repr: self.repr & T::ALL_BITS }
283    }
284}
285
286impl<T: EnumSetTypeWithRepr, const N: usize> From<[T; N]> for MixedEnumSet<T> {
287    fn from(value: [T; N]) -> Self {
288        let mut new = MixedEnumSet::new();
289        for elem in value {
290            new.insert(elem);
291        }
292        new
293    }
294}
295
296impl<T: EnumSetTypeWithRepr> From<EnumSet<T>> for MixedEnumSet<T> {
297    fn from(value: EnumSet<T>) -> Self {
298        MixedEnumSet { repr: value.repr }
299    }
300}
301//endregion
302
303//region EnumSet iter
304/// The iterator used by [`MixedEnumSet`]s.
305#[derive(Clone, Debug)]
306pub struct MixedEnumSetIter<T: EnumSetType> {
307    iter: <T::Repr as EnumSetTypeRepr>::Iter,
308}
309impl<T: EnumSetTypeWithRepr> MixedEnumSetIter<T> {
310    fn new(set: MixedEnumSet<T>) -> MixedEnumSetIter<T> {
311        MixedEnumSetIter { iter: set.repr.iter() }
312    }
313}
314
315impl<T: EnumSetTypeWithRepr> MixedEnumSet<T> {
316    /// Iterates the contents of the set in order from the least significant bit to the most
317    /// significant bit.
318    ///
319    /// Note that iterator invalidation is impossible as the iterator contains a copy of this type,
320    /// rather than holding a reference to it.
321    pub fn iter(&self) -> MixedEnumSetIter<T> {
322        MixedEnumSetIter::new(*self)
323    }
324}
325
326impl<T: EnumSetTypeWithRepr> Iterator for MixedEnumSetIter<T> {
327    type Item = MixedValue<T>;
328
329    fn next(&mut self) -> Option<Self::Item> {
330        self.iter.next().map(|x| MixedValue::from_bit(x))
331    }
332    fn size_hint(&self) -> (usize, Option<usize>) {
333        self.iter.size_hint()
334    }
335}
336impl<T: EnumSetTypeWithRepr> DoubleEndedIterator for MixedEnumSetIter<T> {
337    fn next_back(&mut self) -> Option<Self::Item> {
338        self.iter.next_back().map(|x| MixedValue::from_bit(x))
339    }
340}
341impl<T: EnumSetTypeWithRepr> ExactSizeIterator for MixedEnumSetIter<T> {}
342
343set_iterator_impls!(MixedEnumSet, EnumSetTypeWithRepr);
344
345impl<T: EnumSetTypeWithRepr> IntoIterator for MixedEnumSet<T> {
346    type Item = MixedValue<T>;
347    type IntoIter = MixedEnumSetIter<T>;
348
349    fn into_iter(self) -> Self::IntoIter {
350        self.iter()
351    }
352}
353
354impl<T: EnumSetTypeWithRepr> Extend<EnumSet<T>> for MixedEnumSet<T> {
355    fn extend<I: IntoIterator<Item = EnumSet<T>>>(&mut self, iter: I) {
356        iter.into_iter().for_each(|v| {
357            self.insert_all(v);
358        });
359    }
360}
361
362impl<'a, T: EnumSetTypeWithRepr> Extend<&'a EnumSet<T>> for MixedEnumSet<T> {
363    fn extend<I: IntoIterator<Item = &'a EnumSet<T>>>(&mut self, iter: I) {
364        iter.into_iter().for_each(|v| {
365            self.insert_all(*v);
366        });
367    }
368}
369
370impl<T: EnumSetTypeWithRepr> FromIterator<EnumSet<T>> for MixedEnumSet<T> {
371    fn from_iter<I: IntoIterator<Item = EnumSet<T>>>(iter: I) -> Self {
372        let mut set = MixedEnumSet::default();
373        set.extend(iter);
374        set
375    }
376}
377
378impl<'a, T: 'a + EnumSetTypeWithRepr> FromIterator<&'a EnumSet<T>> for MixedEnumSet<T> {
379    fn from_iter<I: IntoIterator<Item = &'a EnumSet<T>>>(iter: I) -> Self {
380        let mut set = MixedEnumSet::default();
381        set.extend(iter);
382        set
383    }
384}
385
386impl<'a, T: EnumSetTypeWithRepr> Sum<EnumSet<T>> for MixedEnumSet<T> {
387    fn sum<I: Iterator<Item = EnumSet<T>>>(iter: I) -> Self {
388        iter.fold(MixedEnumSet::empty(), |a, v| a | v)
389    }
390}
391
392impl<'a, T: EnumSetTypeWithRepr> Sum<&'a EnumSet<T>> for MixedEnumSet<T> {
393    fn sum<I: Iterator<Item = &'a EnumSet<T>>>(iter: I) -> Self {
394        iter.fold(MixedEnumSet::empty(), |a, v| a | *v)
395    }
396}
397//endregion