Skip to content

Commit 2ddeac7

Browse files
committed
Put const fn-specific APIs in a separate module
1 parent 2e5173b commit 2ddeac7

File tree

2 files changed

+163
-153
lines changed

2 files changed

+163
-153
lines changed

src/const_api.rs

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

src/lib.rs

Lines changed: 3 additions & 153 deletions
Original file line numberDiff line numberDiff line change
@@ -408,6 +408,9 @@ pub use crate::fallible::FromBitsError;
408408
mod iter;
409409
pub use crate::iter::Iter;
410410

411+
mod const_api;
412+
pub use crate::const_api::ConstToken;
413+
411414
/// Represents a set of flags of some type `T`.
412415
/// `T` must have the `#[bitflags]` attribute applied.
413416
///
@@ -548,13 +551,6 @@ impl<T: BitFlag> From<T> for BitFlags<T> {
548551
}
549552
}
550553

551-
/// Workaround for `const fn` limitations.
552-
///
553-
/// Some `const fn`s in this crate will need an instance of this type
554-
/// for some type-level information usually provided by traits.
555-
/// For an example of usage, see [`not_c`][BitFlags::not_c].
556-
pub struct ConstToken<T, N>(BitFlags<T, N>);
557-
558554
impl<T> BitFlags<T>
559555
where
560556
T: BitFlag,
@@ -666,23 +662,6 @@ where
666662
Self::ALL
667663
}
668664

669-
/// An empty `BitFlags`. Equivalent to [`empty()`][BitFlags::empty],
670-
/// but works in a const context.
671-
pub const EMPTY: Self = BitFlags {
672-
val: T::EMPTY,
673-
marker: PhantomData,
674-
};
675-
676-
/// A `BitFlags` with all flags set. Equivalent to [`all()`][BitFlags::all],
677-
/// but works in a const context.
678-
pub const ALL: Self = BitFlags {
679-
val: T::ALL_BITS,
680-
marker: PhantomData,
681-
};
682-
683-
/// A [`ConstToken`] for this type of flag.
684-
pub const CONST_TOKEN: ConstToken<T, T::Numeric> = ConstToken(Self::ALL);
685-
686665
/// Returns true if all flags are set
687666
#[inline(always)]
688667
pub fn is_all(self) -> bool {
@@ -796,135 +775,6 @@ where
796775
}
797776
}
798777

799-
for_each_uint! { $ty $hide_docs =>
800-
impl<T> BitFlags<T, $ty> {
801-
/// Create a new BitFlags unsafely, without checking if the bits form
802-
/// a valid bit pattern for the type.
803-
///
804-
/// Const variant of
805-
/// [`from_bits_unchecked`][BitFlags::from_bits_unchecked].
806-
///
807-
/// Consider using
808-
/// [`from_bits_truncate_c`][BitFlags::from_bits_truncate_c] instead.
809-
///
810-
/// # Safety
811-
///
812-
/// All bits set in `val` must correspond to a value of the enum.
813-
#[must_use]
814-
#[inline(always)]
815-
$(#[$hide_docs])?
816-
pub const unsafe fn from_bits_unchecked_c(
817-
val: $ty, const_token: ConstToken<T, $ty>
818-
) -> Self {
819-
let _ = const_token;
820-
BitFlags {
821-
val,
822-
marker: PhantomData,
823-
}
824-
}
825-
826-
/// Create a `BitFlags<T>` from an underlying bitwise value. If any
827-
/// invalid bits are set, ignore them.
828-
///
829-
/// ```
830-
/// # use enumflags2::{bitflags, BitFlags};
831-
/// #[bitflags]
832-
/// #[repr(u8)]
833-
/// #[derive(Clone, Copy, Debug, PartialEq, Eq)]
834-
/// enum MyFlag {
835-
/// One = 1 << 0,
836-
/// Two = 1 << 1,
837-
/// Three = 1 << 2,
838-
/// }
839-
///
840-
/// const FLAGS: BitFlags<MyFlag> =
841-
/// BitFlags::<MyFlag>::from_bits_truncate_c(0b10101010, BitFlags::CONST_TOKEN);
842-
/// assert_eq!(FLAGS, MyFlag::Two);
843-
/// ```
844-
#[must_use]
845-
#[inline(always)]
846-
$(#[$hide_docs])?
847-
pub const fn from_bits_truncate_c(
848-
bits: $ty, const_token: ConstToken<T, $ty>
849-
) -> Self {
850-
BitFlags {
851-
val: bits & const_token.0.val,
852-
marker: PhantomData,
853-
}
854-
}
855-
856-
/// Bitwise OR — return value contains flag if either argument does.
857-
///
858-
/// Also available as `a | b`, but operator overloads are not usable
859-
/// in `const fn`s at the moment.
860-
#[must_use]
861-
#[inline(always)]
862-
$(#[$hide_docs])?
863-
pub const fn union_c(self, other: Self) -> Self {
864-
BitFlags {
865-
val: self.val | other.val,
866-
marker: PhantomData,
867-
}
868-
}
869-
870-
/// Bitwise AND — return value contains flag if both arguments do.
871-
///
872-
/// Also available as `a & b`, but operator overloads are not usable
873-
/// in `const fn`s at the moment.
874-
#[must_use]
875-
#[inline(always)]
876-
$(#[$hide_docs])?
877-
pub const fn intersection_c(self, other: Self) -> Self {
878-
BitFlags {
879-
val: self.val & other.val,
880-
marker: PhantomData,
881-
}
882-
}
883-
884-
/// Bitwise NOT — return value contains flag if argument doesn't.
885-
///
886-
/// Also available as `!a`, but operator overloads are not usable
887-
/// in `const fn`s at the moment.
888-
///
889-
/// Moreover, due to `const fn` limitations, `not_c` needs a
890-
/// [`ConstToken`] as an argument.
891-
///
892-
/// ```
893-
/// # use enumflags2::{bitflags, BitFlags, make_bitflags};
894-
/// #[bitflags]
895-
/// #[repr(u8)]
896-
/// #[derive(Clone, Copy, Debug, PartialEq, Eq)]
897-
/// enum MyFlag {
898-
/// One = 1 << 0,
899-
/// Two = 1 << 1,
900-
/// Three = 1 << 2,
901-
/// }
902-
///
903-
/// const FLAGS: BitFlags<MyFlag> = make_bitflags!(MyFlag::{One | Two});
904-
/// const NEGATED: BitFlags<MyFlag> = FLAGS.not_c(BitFlags::CONST_TOKEN);
905-
/// assert_eq!(NEGATED, MyFlag::Three);
906-
/// ```
907-
#[must_use]
908-
#[inline(always)]
909-
$(#[$hide_docs])?
910-
pub const fn not_c(self, const_token: ConstToken<T, $ty>) -> Self {
911-
BitFlags {
912-
val: !self.val & const_token.0.val,
913-
marker: PhantomData,
914-
}
915-
}
916-
917-
/// Returns the underlying bitwise value.
918-
///
919-
/// `const` variant of [`bits`][BitFlags::bits].
920-
#[inline(always)]
921-
$(#[$hide_docs])?
922-
pub const fn bits_c(self) -> $ty {
923-
self.val
924-
}
925-
}
926-
}
927-
928778
impl<T, N: PartialEq> PartialEq for BitFlags<T, N> {
929779
#[inline(always)]
930780
fn eq(&self, other: &Self) -> bool {

0 commit comments

Comments
 (0)