|
84 | 84 |
|
85 | 85 | use core::{cmp, ops}; |
86 | 86 | use core::iter::FromIterator; |
| 87 | +use core::marker::PhantomData; |
87 | 88 |
|
88 | 89 | #[allow(unused_imports)] |
89 | 90 | #[macro_use] |
@@ -244,10 +245,84 @@ pub use crate::fallible::FromBitsError; |
244 | 245 |
|
245 | 246 | /// Represents a set of flags of some type `T`. |
246 | 247 | /// `T` must have the `#[bitflags]` attribute applied. |
247 | | -#[derive(Copy, Clone, Eq, Hash)] |
| 248 | +/// |
| 249 | +/// A `BitFlags<T>` is as large as the `T` itself, |
| 250 | +/// and stores one flag per bit. |
| 251 | +/// |
| 252 | +/// ## Memory layout |
| 253 | +/// |
| 254 | +/// `BitFlags<T>` is marked with the `#[repr(transparent)]` trait, meaning |
| 255 | +/// it can be safely transmuted into the corresponding numeric type. |
| 256 | +/// |
| 257 | +/// Usually, the same can be achieved by using [`BitFlags::from_bits`], |
| 258 | +/// [`BitFlags::from_bits_truncated`] or [`BitFlags::from_bits_unchecked`], |
| 259 | +/// but transmuting might still be useful if, for example, you're dealing with |
| 260 | +/// an entire array of `BitFlags`. |
| 261 | +/// |
| 262 | +/// Transmuting from a numeric type into `BitFlags` may also be done, but |
| 263 | +/// care must be taken to make sure that each set bit in the value corresponds |
| 264 | +/// to an existing flag (cf. [`from_bits_unchecked`]). |
| 265 | +/// |
| 266 | +/// For example: |
| 267 | +/// |
| 268 | +/// ``` |
| 269 | +/// # use enumflags2::{BitFlags, bitflags}; |
| 270 | +/// #[bitflags] |
| 271 | +/// #[repr(u8)] // <-- the repr determines the numeric type |
| 272 | +/// #[derive(Copy, Clone)] |
| 273 | +/// enum TransmuteMe { |
| 274 | +/// One = 1 << 0, |
| 275 | +/// Two = 1 << 1, |
| 276 | +/// } |
| 277 | +/// |
| 278 | +/// # use std::slice; |
| 279 | +/// // NOTE: we use a small, self-contained function to handle the slice |
| 280 | +/// // conversion to make sure the lifetimes are right. |
| 281 | +/// fn transmute_slice<'a>(input: &'a [BitFlags<TransmuteMe>]) -> &'a [u8] { |
| 282 | +/// unsafe { |
| 283 | +/// slice::from_raw_parts(input.as_ptr() as *const u8, input.len()) |
| 284 | +/// } |
| 285 | +/// } |
| 286 | +/// |
| 287 | +/// let many_flags = &[ |
| 288 | +/// TransmuteMe::One.into(), |
| 289 | +/// TransmuteMe::One | TransmuteMe::Two, |
| 290 | +/// ]; |
| 291 | +/// |
| 292 | +/// let as_nums = transmute_slice(many_flags); |
| 293 | +/// assert_eq!(as_nums, &[0b01, 0b11]); |
| 294 | +/// ``` |
| 295 | +/// |
| 296 | +/// ## Implementation notes |
| 297 | +/// |
| 298 | +/// You might expect this struct to be defined as |
| 299 | +/// |
| 300 | +/// ```ignore |
| 301 | +/// struct BitFlags<T: BitFlag> { |
| 302 | +/// value: T::Numeric |
| 303 | +/// } |
| 304 | +/// ``` |
| 305 | +/// |
| 306 | +/// Ideally, that would be the case. However, because `const fn`s cannot |
| 307 | +/// have trait bounds in current Rust, this would prevent us from providing |
| 308 | +/// most `const fn` APIs. As a workaround, we define `BitFlags` with two |
| 309 | +/// type parameters, with a default for the second one: |
| 310 | +/// |
| 311 | +/// ```ignore |
| 312 | +/// struct BitFlags<T, N = <T as BitFlag>::Numeric> { |
| 313 | +/// value: N, |
| 314 | +/// marker: PhantomData<T>, |
| 315 | +/// } |
| 316 | +/// ``` |
| 317 | +/// |
| 318 | +/// The types substituted for `T` and `N` must always match, creating a |
| 319 | +/// `BitFlags` value where that isn't the case is considered to be impossible |
| 320 | +/// without unsafe code. |
| 321 | +#[derive(Copy, Clone, Hash)] |
248 | 322 | #[repr(transparent)] |
249 | | -pub struct BitFlags<T: BitFlag> { |
250 | | - val: T::Numeric, |
| 323 | +pub struct BitFlags<T, N = <T as _internal::RawBitFlags>::Numeric> { |
| 324 | + val: N, |
| 325 | + marker: PhantomData<T>, |
251 | 326 | } |
252 | 327 |
|
253 | 328 | /// The default value returned is one with all flags unset, i. e. [`empty`][Self::empty]. |
@@ -280,7 +355,7 @@ where |
280 | 355 | /// The argument must not have set bits at positions not corresponding to |
281 | 356 | /// any flag. |
282 | 357 | pub unsafe fn from_bits_unchecked(val: T::Numeric) -> Self { |
283 | | - BitFlags { val } |
| 358 | + BitFlags { val, marker: PhantomData } |
284 | 359 | } |
285 | 360 |
|
286 | 361 | /// Create a `BitFlags` with no flags set (in other words, with a value of `0`). |
@@ -341,13 +416,13 @@ where |
341 | 416 | /// but works in a const context. |
342 | 417 | /// |
343 | 418 | /// [`empty()`]: #method.empty |
344 | | - pub const EMPTY: Self = BitFlags { val: T::EMPTY }; |
| 419 | + pub const EMPTY: Self = BitFlags { val: T::EMPTY, marker: PhantomData }; |
345 | 420 |
|
346 | 421 | /// A `BitFlags` with all flags set. Equivalent to [`all()`], |
347 | 422 | /// but works in a const context. |
348 | 423 | /// |
349 | 424 | /// [`all()`]: #method.all |
350 | | - pub const ALL: Self = BitFlags { val: T::ALL_BITS }; |
| 425 | + pub const ALL: Self = BitFlags { val: T::ALL_BITS, marker: PhantomData }; |
351 | 426 |
|
352 | 427 | /// Returns true if all flags are set |
353 | 428 | pub fn is_all(self) -> bool { |
|
0 commit comments