Hello! I'm trying to figure out a way of making it possible to construct an enumflags2 BitFlags
in a const
context.
The relevant types look like this:
pub trait BitFlag {
type Numeric;
// also some constants and functions we won't be using today
}
pub struct BitFlags<T: BitFlag> {
val: T::Numeric,
}
The user writes something like this:
#[bitflags]
#[repr(u8)]
#[derive(Clone, Copy, PartialEq, Eq)]
pub enum MyFlag {
Foo = 1 << 0,
Bar = 1 << 1,
Baz = 1 << 2,
}
This expands into an implementation of BitFlag
:
impl BitFlag for MyFlag {
type Numeric = u8;
}
The invariant I want to uphold is that all set bits in val
correspond to a variant of the enum
. As such, I can't just make val
a pub
field.
Currently, most ways of creating a BitFlags
rely on traits: MyFlag::Foo.into()
, MyFlag::Bar | MyFlag::Baz
. Of course, const traits are unstable, so there's no hope of making these work in a const. I'm considering the possibility of providing a macro, like this:
const FLAGS: BitFlags<MyFlag> = bitflags!(MyFlag::{Bar | Baz});
This way, I can hide arbitrary amounts of sausage-factory detail in the macro. However, I would still need a way, even most primitive, to construct a BitFlags
. This is quite hard, as even a function as simple as
impl<T: BitFlag> BitFlags<T> {
const unsafe fn new_unchecked(val: T::Numeric) -> Self {
BitFlags { val }
}
}
errors out with
error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable
--> src/lib.rs:9:6
|
9 | impl<T: BitFlag> BitFlags<T> {
| ^
|
= note: see issue #57563 <https://github.com/rust-lang/rust/issues/57563> for more information
= help: add `#![feature(const_fn)]` to the crate attributes to enable
At this point I can only see two options:
- firstly, perhaps there is a way to use hygiene tricks to convince rustc that the code generated by the
bitflags!
macro comes from the same crate as the definition ofBitFlags
, letting me construct the value withBitFlags { val: _ }
in the macro? - alternatively, I could make the field
pub
, but name it something like_internal_value
and give it a#[doc(hidden)]
attribute. FWIW, this is similar to what is already being done with some traits used by#[bitflags]
, but I'd still rather avoid this, as a field like this is more likely to interfere in an IDE than anenumflags2::_internal
module...
Dear Rust wizards, what shall I do?