| 1 | use crate::{BitFlags, BitFlag}; |
| 2 | use core::marker::PhantomData; |
| 3 | |
| 4 | /// Workaround for `const fn` limitations. |
| 5 | /// |
| 6 | /// Some `const fn`s in this crate will need an instance of this type |
| 7 | /// for some type-level information usually provided by traits. |
| 8 | /// |
| 9 | /// A token can be obtained from [`BitFlags::CONST_TOKEN`]. The relevant types |
| 10 | /// should be readily inferred from context. |
| 11 | /// |
| 12 | /// For an example of usage, see [`not_c`][BitFlags::not_c]. |
| 13 | pub struct ConstToken<T, N>(BitFlags<T, N>); |
| 14 | |
| 15 | impl<T> BitFlags<T> |
| 16 | where |
| 17 | T: BitFlag, |
| 18 | { |
| 19 | /// An empty `BitFlags`. Equivalent to [`empty()`][BitFlags::empty], |
| 20 | /// but works in a const context. |
| 21 | pub const EMPTY: Self = BitFlags { |
| 22 | val: T::EMPTY, |
| 23 | marker: PhantomData, |
| 24 | }; |
| 25 | |
| 26 | /// A `BitFlags` with all flags set. Equivalent to [`all()`][BitFlags::all], |
| 27 | /// but works in a const context. |
| 28 | pub const ALL: Self = BitFlags { |
| 29 | val: T::ALL_BITS, |
| 30 | marker: PhantomData, |
| 31 | }; |
| 32 | |
| 33 | /// A [`ConstToken`] for this type of flag. |
| 34 | pub const CONST_TOKEN: ConstToken<T, T::Numeric> = ConstToken(Self::ALL); |
| 35 | } |
| 36 | |
| 37 | for_each_uint! { $ty $hide_docs => |
| 38 | impl<T> BitFlags<T, $ty> { |
| 39 | /// Create a new BitFlags unsafely, without checking if the bits form |
| 40 | /// a valid bit pattern for the type. |
| 41 | /// |
| 42 | /// Const variant of |
| 43 | /// [`from_bits_unchecked`][BitFlags::from_bits_unchecked]. |
| 44 | /// |
| 45 | /// Consider using |
| 46 | /// [`from_bits_truncate_c`][BitFlags::from_bits_truncate_c] instead. |
| 47 | /// |
| 48 | /// # Safety |
| 49 | /// |
| 50 | /// All bits set in `val` must correspond to a value of the enum. |
| 51 | #[must_use] |
| 52 | #[inline(always)] |
| 53 | $(#[$hide_docs])? |
| 54 | pub const unsafe fn from_bits_unchecked_c( |
| 55 | val: $ty, const_token: ConstToken<T, $ty> |
| 56 | ) -> Self { |
| 57 | let _ = const_token; |
| 58 | BitFlags { |
| 59 | val, |
| 60 | marker: PhantomData, |
| 61 | } |
| 62 | } |
| 63 | |
| 64 | /// Create a `BitFlags<T>` from an underlying bitwise value. If any |
| 65 | /// invalid bits are set, ignore them. |
| 66 | /// |
| 67 | /// ``` |
| 68 | /// # use enumflags2::{bitflags, BitFlags}; |
| 69 | /// #[bitflags] |
| 70 | /// #[repr(u8)] |
| 71 | /// #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 72 | /// enum MyFlag { |
| 73 | /// One = 1 << 0, |
| 74 | /// Two = 1 << 1, |
| 75 | /// Three = 1 << 2, |
| 76 | /// } |
| 77 | /// |
| 78 | /// const FLAGS: BitFlags<MyFlag> = |
| 79 | /// BitFlags::<MyFlag>::from_bits_truncate_c(0b10101010, BitFlags::CONST_TOKEN); |
| 80 | /// assert_eq!(FLAGS, MyFlag::Two); |
| 81 | /// ``` |
| 82 | #[must_use] |
| 83 | #[inline(always)] |
| 84 | $(#[$hide_docs])? |
| 85 | pub const fn from_bits_truncate_c( |
| 86 | bits: $ty, const_token: ConstToken<T, $ty> |
| 87 | ) -> Self { |
| 88 | BitFlags { |
| 89 | val: bits & const_token.0.val, |
| 90 | marker: PhantomData, |
| 91 | } |
| 92 | } |
| 93 | |
| 94 | /// Bitwise OR — return value contains flag if either argument does. |
| 95 | /// |
| 96 | /// Also available as `a | b`, but operator overloads are not usable |
| 97 | /// in `const fn`s at the moment. |
| 98 | #[must_use] |
| 99 | #[inline(always)] |
| 100 | $(#[$hide_docs])? |
| 101 | pub const fn union_c(self, other: Self) -> Self { |
| 102 | BitFlags { |
| 103 | val: self.val | other.val, |
| 104 | marker: PhantomData, |
| 105 | } |
| 106 | } |
| 107 | |
| 108 | /// Bitwise AND — return value contains flag if both arguments do. |
| 109 | /// |
| 110 | /// Also available as `a & b`, but operator overloads are not usable |
| 111 | /// in `const fn`s at the moment. |
| 112 | #[must_use] |
| 113 | #[inline(always)] |
| 114 | $(#[$hide_docs])? |
| 115 | pub const fn intersection_c(self, other: Self) -> Self { |
| 116 | BitFlags { |
| 117 | val: self.val & other.val, |
| 118 | marker: PhantomData, |
| 119 | } |
| 120 | } |
| 121 | |
| 122 | /// Bitwise NOT — return value contains flag if argument doesn't. |
| 123 | /// |
| 124 | /// Also available as `!a`, but operator overloads are not usable |
| 125 | /// in `const fn`s at the moment. |
| 126 | /// |
| 127 | /// Moreover, due to `const fn` limitations, `not_c` needs a |
| 128 | /// [`ConstToken`] as an argument. |
| 129 | /// |
| 130 | /// ``` |
| 131 | /// # use enumflags2::{bitflags, BitFlags, make_bitflags}; |
| 132 | /// #[bitflags] |
| 133 | /// #[repr(u8)] |
| 134 | /// #[derive(Clone, Copy, Debug, PartialEq, Eq)] |
| 135 | /// enum MyFlag { |
| 136 | /// One = 1 << 0, |
| 137 | /// Two = 1 << 1, |
| 138 | /// Three = 1 << 2, |
| 139 | /// } |
| 140 | /// |
| 141 | /// const FLAGS: BitFlags<MyFlag> = make_bitflags!(MyFlag::{One | Two}); |
| 142 | /// const NEGATED: BitFlags<MyFlag> = FLAGS.not_c(BitFlags::CONST_TOKEN); |
| 143 | /// assert_eq!(NEGATED, MyFlag::Three); |
| 144 | /// ``` |
| 145 | #[must_use] |
| 146 | #[inline(always)] |
| 147 | $(#[$hide_docs])? |
| 148 | pub const fn not_c(self, const_token: ConstToken<T, $ty>) -> Self { |
| 149 | BitFlags { |
| 150 | val: !self.val & const_token.0.val, |
| 151 | marker: PhantomData, |
| 152 | } |
| 153 | } |
| 154 | |
| 155 | /// Returns the underlying bitwise value. |
| 156 | /// |
| 157 | /// `const` variant of [`bits`][BitFlags::bits]. |
| 158 | #[inline(always)] |
| 159 | $(#[$hide_docs])? |
| 160 | pub const fn bits_c(self) -> $ty { |
| 161 | self.val |
| 162 | } |
| 163 | } |
| 164 | } |
| 165 | |