enumflags2/
const_api.rs

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}