1use crate::{BitFlags, BitFlag};
2use 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].
13pub struct ConstToken<T, N>(BitFlags<T, N>);
14
15impl<T> BitFlags<T>
16where
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
37for_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