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 | |