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 Deprecated functions
236/// This impl contains all outdated or deprecated functions.
237impl<T: EnumSetTypeWithRepr> MixedEnumSet<T> {
238    /// Returns a set containing every element present in either `self` or `other`, but not
239    /// present in both.
240    #[inline(always)]
241    #[deprecated(since = "1.1.13", note = "Use `symmetric_difference` instead.")]
242    pub fn symmetrical_difference(&self, other: impl Into<Self>) -> Self {
243        self.symmetric_difference(other)
244    }
245}
246//endregion
247
248//region MixedEnumSet conversions
249impl<T: EnumSetTypeWithRepr> MixedEnumSet<T> {
250    /// Returns a `T::Repr` representing the elements of this set.
251    ///
252    /// Unlike the other `as_*` methods, this method is zero-cost and guaranteed not to fail,
253    /// panic or truncate any bits.
254    #[inline(always)]
255    pub const fn as_repr(&self) -> <T as EnumSetTypeWithRepr>::Repr {
256        self.repr
257    }
258
259    /// Constructs a bitset from a `T::Repr`.
260    #[inline(always)]
261    pub fn from_repr(bits: <T as EnumSetTypeWithRepr>::Repr) -> Self {
262        Self { repr: bits }
263    }
264
265    /// Constructs a bitset from a `T::Repr`, ignoring invalid variants.
266    #[inline(always)]
267    pub fn from_repr_truncated(bits: <T as EnumSetTypeWithRepr>::Repr) -> Self {
268        let mask = Self::all().as_repr();
269        let bits = bits & mask;
270        MixedEnumSet { repr: bits }
271    }
272
273    /// Converts this set into the corresponding [`EnumSet`].
274    ///
275    /// If any unknown bits are present in the set, this method will panic.
276    pub fn as_enumset(&self) -> EnumSet<T> {
277        self.try_as_enumset()
278            .expect("Bitset contains invalid variants.")
279    }
280
281    /// Attempts to convert this set into the corresponding [`EnumSet`].
282    ///
283    /// If any unknown bits are present in the set, this method will return `None`.
284    pub fn try_as_enumset(&self) -> Option<EnumSet<T>> {
285        if self.has_unknown_bits() {
286            None
287        } else {
288            Some(EnumSet { repr: self.repr })
289        }
290    }
291
292    /// Converts this set into the corresponding [`EnumSet`], ignoring bits that do not correspond
293    /// to a variant.
294    pub fn as_enumset_truncate(&self) -> EnumSet<T> {
295        EnumSet { repr: self.repr & T::ALL_BITS }
296    }
297}
298
299impl<T: EnumSetTypeWithRepr, const N: usize> From<[T; N]> for MixedEnumSet<T> {
300    fn from(value: [T; N]) -> Self {
301        let mut new = MixedEnumSet::new();
302        for elem in value {
303            new.insert(elem);
304        }
305        new
306    }
307}
308
309impl<T: EnumSetTypeWithRepr> From<EnumSet<T>> for MixedEnumSet<T> {
310    fn from(value: EnumSet<T>) -> Self {
311        MixedEnumSet { repr: value.repr }
312    }
313}
314//endregion
315
316//region EnumSet iter
317/// The iterator used by [`MixedEnumSet`]s.
318#[derive(Clone, Debug)]
319pub struct MixedEnumSetIter<T: EnumSetType> {
320    iter: <T::Repr as EnumSetTypeRepr>::Iter,
321}
322impl<T: EnumSetTypeWithRepr> MixedEnumSetIter<T> {
323    fn new(set: MixedEnumSet<T>) -> MixedEnumSetIter<T> {
324        MixedEnumSetIter { iter: set.repr.iter() }
325    }
326}
327
328impl<T: EnumSetTypeWithRepr> MixedEnumSet<T> {
329    /// Iterates the contents of the set in order from the least significant bit to the most
330    /// significant bit.
331    ///
332    /// Note that iterator invalidation is impossible as the iterator contains a copy of this type,
333    /// rather than holding a reference to it.
334    pub fn iter(&self) -> MixedEnumSetIter<T> {
335        MixedEnumSetIter::new(*self)
336    }
337}
338
339impl<T: EnumSetTypeWithRepr> Iterator for MixedEnumSetIter<T> {
340    type Item = MixedValue<T>;
341
342    fn next(&mut self) -> Option<Self::Item> {
343        self.iter.next().map(|x| MixedValue::from_bit(x))
344    }
345    fn size_hint(&self) -> (usize, Option<usize>) {
346        self.iter.size_hint()
347    }
348}
349impl<T: EnumSetTypeWithRepr> DoubleEndedIterator for MixedEnumSetIter<T> {
350    fn next_back(&mut self) -> Option<Self::Item> {
351        self.iter.next_back().map(|x| MixedValue::from_bit(x))
352    }
353}
354impl<T: EnumSetTypeWithRepr> ExactSizeIterator for MixedEnumSetIter<T> {}
355
356set_iterator_impls!(MixedEnumSet, EnumSetTypeWithRepr);
357
358impl<T: EnumSetTypeWithRepr> IntoIterator for MixedEnumSet<T> {
359    type Item = MixedValue<T>;
360    type IntoIter = MixedEnumSetIter<T>;
361
362    fn into_iter(self) -> Self::IntoIter {
363        self.iter()
364    }
365}
366
367impl<T: EnumSetTypeWithRepr> Extend<EnumSet<T>> for MixedEnumSet<T> {
368    fn extend<I: IntoIterator<Item = EnumSet<T>>>(&mut self, iter: I) {
369        iter.into_iter().for_each(|v| {
370            self.insert_all(v);
371        });
372    }
373}
374
375impl<'a, T: EnumSetTypeWithRepr> Extend<&'a EnumSet<T>> for MixedEnumSet<T> {
376    fn extend<I: IntoIterator<Item = &'a EnumSet<T>>>(&mut self, iter: I) {
377        iter.into_iter().for_each(|v| {
378            self.insert_all(*v);
379        });
380    }
381}
382
383impl<T: EnumSetTypeWithRepr> FromIterator<EnumSet<T>> for MixedEnumSet<T> {
384    fn from_iter<I: IntoIterator<Item = EnumSet<T>>>(iter: I) -> Self {
385        let mut set = MixedEnumSet::default();
386        set.extend(iter);
387        set
388    }
389}
390
391impl<'a, T: 'a + EnumSetTypeWithRepr> FromIterator<&'a EnumSet<T>> for MixedEnumSet<T> {
392    fn from_iter<I: IntoIterator<Item = &'a EnumSet<T>>>(iter: I) -> Self {
393        let mut set = MixedEnumSet::default();
394        set.extend(iter);
395        set
396    }
397}
398
399impl<'a, T: EnumSetTypeWithRepr> Sum<EnumSet<T>> for MixedEnumSet<T> {
400    fn sum<I: Iterator<Item = EnumSet<T>>>(iter: I) -> Self {
401        iter.fold(MixedEnumSet::empty(), |a, v| a | v)
402    }
403}
404
405impl<'a, T: EnumSetTypeWithRepr> Sum<&'a EnumSet<T>> for MixedEnumSet<T> {
406    fn sum<I: Iterator<Item = &'a EnumSet<T>>>(iter: I) -> Self {
407        iter.fold(MixedEnumSet::empty(), |a, v| a | *v)
408    }
409}
410//endregion