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