flagset/lib.rs
1//
2// Copyright 2019 Red Hat, Inc.
3//
4// Author: Nathaniel McCallum <npmccallum@redhat.com>
5//
6// Licensed under the Apache License, Version 2.0 (the "License");
7// you may not use this file except in compliance with the License.
8// You may obtain a copy of the License at
9//
10// http://www.apache.org/licenses/LICENSE-2.0
11//
12// Unless required by applicable law or agreed to in writing, software
13// distributed under the License is distributed on an "AS IS" BASIS,
14// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15// See the License for the specific language governing permissions and
16// limitations under the License.
17//
18
19//! # Welcome to FlagSet!
20//!
21//! FlagSet is a new, ergonomic approach to handling flags that combines the
22//! best of existing crates like `bitflags` and `enumflags` without their
23//! downsides.
24//!
25//! ## Existing Implementations
26//!
27//! The `bitflags` crate has long been part of the Rust ecosystem.
28//! Unfortunately, it doesn't feel like natural Rust. The `bitflags` crate
29//! uses a wierd struct format to define flags. Flags themselves are just
30//! integers constants, so there is little type-safety involved. But it doesn't
31//! have any dependencies. It also allows you to define implied flags (otherwise
32//! known as overlapping flags).
33//!
34//! The `enumflags` crate tried to improve on `bitflags` by using enumerations
35//! to define flags. This was a big improvement to the natural feel of the code.
36//! Unfortunately, there are some design flaws. To generate the flags,
37//! procedural macros were used. This implied two separate crates plus
38//! additional dependencies. Further, `enumflags` specifies the size of the
39//! flags using a `repr($size)` attribute. Unfortunately, this attribute
40//! cannot resolve type aliases, such as `c_int`. This makes `enumflags` a
41//! poor fit for FFI, which is the most important place for a flags library.
42//! The `enumflags` crate also disallows overlapping flags and is not
43//! maintained.
44//!
45//! FlagSet improves on both of these by adopting the `enumflags` natural feel
46//! and the `bitflags` mode of flag generation; as well as additional API usage
47//! niceties. FlagSet has no dependencies and is extensively documented and
48//! tested. It also tries very hard to prevent you from making mistakes by
49//! avoiding external usage of the integer types. FlagSet is also a zero-cost
50//! abstraction: all functions are inlineable and should reduce to the core
51//! integer operations. FlagSet also does not depend on stdlib, so it can be
52//! used in `no_std` libraries and applications.
53//!
54//! ## Defining Flags
55//!
56//! Flags are defined using the `flags!` macro:
57//!
58//! ```
59//! use flagset::{FlagSet, flags};
60//! use std::os::raw::c_int;
61//!
62//! flags! {
63//! enum FlagsA: u8 {
64//! Foo,
65//! Bar,
66//! Baz,
67//! }
68//!
69//! enum FlagsB: c_int {
70//! Foo,
71//! Bar,
72//! Baz,
73//! }
74//! }
75//! ```
76//!
77//! Notice that a flag definition looks just like a regular enumeration, with
78//! the addition of the field-size type. The field-size type is required and
79//! can be either a type or a type alias. Both examples are given above.
80//!
81//! Also note that the field-size type specifies the size of the corresponding
82//! `FlagSet` type, not size of the enumeration itself. To specify the size of
83//! the enumeration, use the `repr($size)` attribute as specified below.
84//!
85//! ## Flag Values
86//!
87//! Flags often need values assigned to them. This can be done implicitly,
88//! where the value depends on the order of the flags:
89//!
90//! ```
91//! use flagset::{FlagSet, flags};
92//!
93//! flags! {
94//! enum Flags: u16 {
95//! Foo, // Implicit Value: 0b0001
96//! Bar, // Implicit Value: 0b0010
97//! Baz, // Implicit Value: 0b0100
98//! }
99//! }
100//! ```
101//!
102//! Alternatively, flag values can be defined explicitly, by specifying any
103//! `const` expression:
104//!
105//! ```
106//! use flagset::{FlagSet, flags};
107//!
108//! flags! {
109//! enum Flags: u16 {
110//! Foo = 0x01, // Explicit Value: 0b0001
111//! Bar = 2, // Explicit Value: 0b0010
112//! Baz = 0b0100, // Explicit Value: 0b0100
113//! }
114//! }
115//! ```
116//!
117//! Flags can also overlap or "imply" other flags:
118//!
119//! ```
120//! use flagset::{FlagSet, flags};
121//!
122//! flags! {
123//! enum Flags: u16 {
124//! Foo = 0b0001,
125//! Bar = 0b0010,
126//! Baz = 0b0110, // Implies Bar
127//! All = (Flags::Foo | Flags::Bar | Flags::Baz).bits(),
128//! }
129//! }
130//! ```
131//!
132//! ## Specifying Attributes
133//!
134//! Attributes can be used on the enumeration itself or any of the values:
135//!
136//! ```
137//! use flagset::{FlagSet, flags};
138//!
139//! flags! {
140//! #[derive(PartialOrd, Ord)]
141//! enum Flags: u8 {
142//! Foo,
143//! #[deprecated]
144//! Bar,
145//! Baz,
146//! }
147//! }
148//! ```
149//!
150//! ## Collections of Flags
151//!
152//! A collection of flags is a `FlagSet<T>`. If you are storing the flags in
153//! memory, the raw `FlagSet<T>` type should be used. However, if you want to
154//! receive flags as an input to a function, you should use
155//! `impl Into<FlagSet<T>>`. This allows for very ergonomic APIs:
156//!
157//! ```
158//! use flagset::{FlagSet, flags};
159//!
160//! flags! {
161//! enum Flags: u8 {
162//! Foo,
163//! Bar,
164//! Baz,
165//! }
166//! }
167//!
168//! struct Container(FlagSet<Flags>);
169//!
170//! impl Container {
171//! fn new(flags: impl Into<FlagSet<Flags>>) -> Container {
172//! Container(flags.into())
173//! }
174//! }
175//!
176//! assert_eq!(Container::new(Flags::Foo | Flags::Bar).0.bits(), 0b011);
177//! assert_eq!(Container::new(Flags::Foo).0.bits(), 0b001);
178//! assert_eq!(Container::new(None).0.bits(), 0b000);
179//! ```
180//!
181//! ## Operations
182//!
183//! Operations can be performed on a `FlagSet<F>` or on individual flags:
184//!
185//! | Operator | Assignment Operator | Meaning |
186//! |----------|---------------------|------------------------|
187//! | \| | \|= | Union |
188//! | & | &= | Intersection |
189//! | ^ | ^= | Toggle specified flags |
190//! | - | -= | Difference |
191//! | % | %= | Symmetric difference |
192//! | ! | | Toggle all flags |
193//!
194#![cfg_attr(
195 feature = "serde",
196 doc = r#"
197
198## Optional Serde support
199
200[Serde] support can be enabled with the 'serde' feature flag. You can then serialize and
201deserialize `FlagSet<T>` to and from any of the [supported formats]:
202
203 ```
204 use flagset::{FlagSet, flags};
205
206 flags! {
207 enum Flags: u8 {
208 Foo,
209 Bar,
210 }
211 }
212
213 let flagset = Flags::Foo | Flags::Bar;
214 let json = serde_json::to_string(&flagset).unwrap();
215 let flagset: FlagSet<Flags> = serde_json::from_str(&json).unwrap();
216 assert_eq!(flagset.bits(), 0b011);
217 ```
218
219For serialization and deserialization of flags enum itself, you can use the [`serde_repr`] crate
220(or implement `serde::ser::Serialize` and `serde:de::Deserialize` manually), combined with the
221appropriate `repr` attribute:
222
223 ```
224 use flagset::{FlagSet, flags};
225 use serde_repr::{Serialize_repr, Deserialize_repr};
226
227 flags! {
228 #[repr(u8)]
229 #[derive(Deserialize_repr, Serialize_repr)]
230 enum Flags: u8 {
231 Foo,
232 Bar,
233 }
234 }
235
236 let json = serde_json::to_string(&Flags::Foo).unwrap();
237 let flag: Flags = serde_json::from_str(&json).unwrap();
238 assert_eq!(flag, Flags::Foo);
239 ```
240
241[Serde]: https://serde.rs/
242[supported formats]: https://serde.rs/#data-formats
243[`serde_repr`]: https://crates.io/crates/serde_repr
244"#
245)]
246#![allow(unknown_lints)]
247#![warn(clippy::all)]
248#![cfg_attr(not(feature = "std"), no_std)]
249#![cfg_attr(docsrs, feature(doc_auto_cfg))]
250
251use core::fmt::{Debug, Formatter, Result};
252use core::ops::*;
253
254/// Error type returned when creating a new flagset from bits is invalid or undefined.
255/// ```
256/// use flagset::{FlagSet, flags};
257///
258/// flags! {
259/// pub enum Flag: u16 {
260/// Foo = 0b0001,
261/// Bar = 0b0010,
262/// Baz = 0b0100,
263/// Qux = 0b1010, // Implies Bar
264/// }
265/// }
266///
267/// assert_eq!(FlagSet::<Flag>::new(0b01101), Err(flagset::InvalidBits)); // Invalid
268/// assert_eq!(FlagSet::<Flag>::new(0b10101), Err(flagset::InvalidBits)); // Unknown
269/// ```
270#[derive(Clone, Copy, Debug, Eq, PartialEq)]
271pub struct InvalidBits;
272
273impl core::fmt::Display for InvalidBits {
274 #[inline]
275 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
276 write!(f, "invalid bits")
277 }
278}
279
280#[cfg(feature = "std")]
281impl std::error::Error for InvalidBits {}
282
283#[doc(hidden)]
284pub trait Flags:
285 Copy
286 + Clone
287 + Debug
288 + PartialEq
289 + Eq
290 + BitAnd<Self, Output = FlagSet<Self>>
291 + BitOr<Self, Output = FlagSet<Self>>
292 + BitXor<Self, Output = FlagSet<Self>>
293 + Sub<Self, Output = FlagSet<Self>>
294 + Rem<Self, Output = FlagSet<Self>>
295 + Not<Output = FlagSet<Self>>
296 + Into<FlagSet<Self>>
297 + 'static
298{
299 type Type: Copy
300 + Clone
301 + Debug
302 + PartialEq
303 + Eq
304 + Default
305 + BitAnd<Self::Type, Output = Self::Type>
306 + BitAndAssign<Self::Type>
307 + BitOr<Self::Type, Output = Self::Type>
308 + BitOrAssign<Self::Type>
309 + BitXor<Self::Type, Output = Self::Type>
310 + BitXorAssign<Self::Type>
311 + Not<Output = Self::Type>;
312
313 /// A slice containing all the possible flag values.
314 const LIST: &'static [Self];
315
316 /// Creates an empty `FlagSet` of this type
317 #[inline]
318 fn none() -> FlagSet<Self> {
319 FlagSet::default()
320 }
321}
322
323#[repr(C)]
324#[derive(Copy, Clone, Eq, Hash)]
325pub struct FlagSet<F: Flags>(F::Type);
326
327#[doc(hidden)]
328#[derive(Copy, Clone)]
329pub struct Iter<F: Flags>(FlagSet<F>, usize);
330
331impl<F: Flags> Iterator for Iter<F> {
332 type Item = F;
333
334 #[inline]
335 fn next(&mut self) -> Option<Self::Item> {
336 while self.1 < F::LIST.len() {
337 let next = F::LIST[self.1];
338 self.1 += 1;
339
340 if self.0.contains(next) {
341 return Some(next);
342 }
343 }
344
345 None
346 }
347}
348
349impl<F: Flags> IntoIterator for FlagSet<F> {
350 type Item = F;
351 type IntoIter = Iter<F>;
352
353 /// Iterate over the flags in the set.
354 ///
355 /// **NOTE**: The order in which the flags are iterated is undefined.
356 ///
357 /// ```
358 /// use flagset::{FlagSet, flags};
359 ///
360 /// flags! {
361 /// enum Flag: u8 {
362 /// Foo = 0b001,
363 /// Bar = 0b010,
364 /// Baz = 0b100
365 /// }
366 /// }
367 ///
368 /// let set = Flag::Foo | Flag::Bar;
369 /// let mut iter = set.into_iter();
370 /// assert_eq!(iter.next(), Some(Flag::Foo));
371 /// assert_eq!(iter.next(), Some(Flag::Bar));
372 /// assert_eq!(iter.next(), None);
373 /// ```
374 #[inline]
375 fn into_iter(self) -> Self::IntoIter {
376 Iter(self, 0)
377 }
378}
379
380impl<F: Flags> Debug for FlagSet<F> {
381 #[inline]
382 fn fmt(&self, f: &mut Formatter) -> Result {
383 write!(f, "FlagSet(")?;
384 for (i, flag) in self.into_iter().enumerate() {
385 write!(f, "{}{:?}", if i > 0 { " | " } else { "" }, flag)?;
386 }
387 write!(f, ")")
388 }
389}
390
391impl<F: Flags, R: Copy + Into<FlagSet<F>>> PartialEq<R> for FlagSet<F> {
392 #[inline]
393 fn eq(&self, rhs: &R) -> bool {
394 self.0 == (*rhs).into().0
395 }
396}
397
398impl<F: Flags> AsRef<F::Type> for FlagSet<F> {
399 #[inline]
400 fn as_ref(&self) -> &F::Type {
401 &self.0
402 }
403}
404
405impl<F: Flags> From<Option<FlagSet<F>>> for FlagSet<F> {
406 /// Converts from `Option<FlagSet<F>>` to `FlagSet<F>`.
407 ///
408 /// Most notably, this allows for the use of `None` in many places to
409 /// substitute for manually creating an empty `FlagSet<F>`. See below.
410 ///
411 /// ```
412 /// use flagset::{FlagSet, flags};
413 ///
414 /// flags! {
415 /// enum Flag: u8 {
416 /// Foo = 0b001,
417 /// Bar = 0b010,
418 /// Baz = 0b100
419 /// }
420 /// }
421 ///
422 /// fn convert(v: impl Into<FlagSet<Flag>>) -> u8 {
423 /// v.into().bits()
424 /// }
425 ///
426 /// assert_eq!(convert(Flag::Foo | Flag::Bar), 0b011);
427 /// assert_eq!(convert(Flag::Foo), 0b001);
428 /// assert_eq!(convert(None), 0b000);
429 /// ```
430 #[inline]
431 fn from(value: Option<FlagSet<F>>) -> FlagSet<F> {
432 value.unwrap_or_default()
433 }
434}
435
436impl<F: Flags> Default for FlagSet<F> {
437 /// Creates a new, empty FlagSet.
438 ///
439 /// ```
440 /// use flagset::{FlagSet, flags};
441 ///
442 /// flags! {
443 /// enum Flag: u8 {
444 /// Foo = 0b001,
445 /// Bar = 0b010,
446 /// Baz = 0b100
447 /// }
448 /// }
449 ///
450 /// let set = FlagSet::<Flag>::default();
451 /// assert!(set.is_empty());
452 /// assert!(!set.is_full());
453 /// assert!(!set.contains(Flag::Foo));
454 /// assert!(!set.contains(Flag::Bar));
455 /// assert!(!set.contains(Flag::Baz));
456 /// ```
457 #[inline]
458 fn default() -> Self {
459 FlagSet(F::Type::default())
460 }
461}
462
463impl<F: Flags> Not for FlagSet<F> {
464 type Output = Self;
465
466 /// Calculates the complement of the current set.
467 ///
468 /// In common parlance, this returns the set of all possible flags that are
469 /// not in the current set.
470 ///
471 /// ```
472 /// use flagset::{FlagSet, flags};
473 ///
474 /// flags! {
475 /// #[derive(PartialOrd, Ord)]
476 /// enum Flag: u8 {
477 /// Foo = 1 << 0,
478 /// Bar = 1 << 1,
479 /// Baz = 1 << 2
480 /// }
481 /// }
482 ///
483 /// let set = !FlagSet::from(Flag::Foo);
484 /// assert!(!set.is_empty());
485 /// assert!(!set.is_full());
486 /// assert!(!set.contains(Flag::Foo));
487 /// assert!(set.contains(Flag::Bar));
488 /// assert!(set.contains(Flag::Baz));
489 /// ```
490 #[inline]
491 fn not(self) -> Self {
492 FlagSet(!self.0)
493 }
494}
495
496impl<F: Flags, R: Into<FlagSet<F>>> BitAnd<R> for FlagSet<F> {
497 type Output = Self;
498
499 /// Calculates the intersection of the current set and the specified flags.
500 ///
501 /// ```
502 /// use flagset::{FlagSet, flags};
503 ///
504 /// flags! {
505 /// #[derive(PartialOrd, Ord)]
506 /// pub enum Flag: u8 {
507 /// Foo = 0b001,
508 /// Bar = 0b010,
509 /// Baz = 0b100
510 /// }
511 /// }
512 ///
513 /// let set0 = Flag::Foo | Flag::Bar;
514 /// let set1 = Flag::Baz | Flag::Bar;
515 /// assert_eq!(set0 & set1, Flag::Bar);
516 /// assert_eq!(set0 & Flag::Foo, Flag::Foo);
517 /// assert_eq!(set1 & Flag::Baz, Flag::Baz);
518 /// ```
519 #[inline]
520 fn bitand(self, rhs: R) -> Self {
521 FlagSet(self.0 & rhs.into().0)
522 }
523}
524
525impl<F: Flags, R: Into<FlagSet<F>>> BitAndAssign<R> for FlagSet<F> {
526 /// Assigns the intersection of the current set and the specified flags.
527 ///
528 /// ```
529 /// use flagset::{FlagSet, flags};
530 ///
531 /// flags! {
532 /// enum Flag: u64 {
533 /// Foo = 0b001,
534 /// Bar = 0b010,
535 /// Baz = 0b100
536 /// }
537 /// }
538 ///
539 /// let mut set0 = Flag::Foo | Flag::Bar;
540 /// let mut set1 = Flag::Baz | Flag::Bar;
541 ///
542 /// set0 &= set1;
543 /// assert_eq!(set0, Flag::Bar);
544 ///
545 /// set1 &= Flag::Baz;
546 /// assert_eq!(set0, Flag::Bar);
547 /// ```
548 #[inline]
549 fn bitand_assign(&mut self, rhs: R) {
550 self.0 &= rhs.into().0
551 }
552}
553
554impl<F: Flags, R: Into<FlagSet<F>>> BitOr<R> for FlagSet<F> {
555 type Output = Self;
556
557 /// Calculates the union of the current set with the specified flags.
558 ///
559 /// ```
560 /// use flagset::{FlagSet, flags};
561 ///
562 /// flags! {
563 /// #[derive(PartialOrd, Ord)]
564 /// pub enum Flag: u8 {
565 /// Foo = 0b001,
566 /// Bar = 0b010,
567 /// Baz = 0b100
568 /// }
569 /// }
570 ///
571 /// let set0 = Flag::Foo | Flag::Bar;
572 /// let set1 = Flag::Baz | Flag::Bar;
573 /// assert_eq!(set0 | set1, FlagSet::full());
574 /// ```
575 #[inline]
576 fn bitor(self, rhs: R) -> Self {
577 FlagSet(self.0 | rhs.into().0)
578 }
579}
580
581impl<F: Flags, R: Into<FlagSet<F>>> BitOrAssign<R> for FlagSet<F> {
582 /// Assigns the union of the current set with the specified flags.
583 ///
584 /// ```
585 /// use flagset::{FlagSet, flags};
586 ///
587 /// flags! {
588 /// enum Flag: u64 {
589 /// Foo = 0b001,
590 /// Bar = 0b010,
591 /// Baz = 0b100
592 /// }
593 /// }
594 ///
595 /// let mut set0 = Flag::Foo | Flag::Bar;
596 /// let mut set1 = Flag::Bar | Flag::Baz;
597 ///
598 /// set0 |= set1;
599 /// assert_eq!(set0, FlagSet::full());
600 ///
601 /// set1 |= Flag::Baz;
602 /// assert_eq!(set1, Flag::Bar | Flag::Baz);
603 /// ```
604 #[inline]
605 fn bitor_assign(&mut self, rhs: R) {
606 self.0 |= rhs.into().0
607 }
608}
609
610impl<F: Flags, R: Into<FlagSet<F>>> BitXor<R> for FlagSet<F> {
611 type Output = Self;
612
613 /// Calculates the current set with the specified flags toggled.
614 ///
615 /// This is commonly known as toggling the presence
616 ///
617 /// ```
618 /// use flagset::{FlagSet, flags};
619 ///
620 /// flags! {
621 /// enum Flag: u32 {
622 /// Foo = 0b001,
623 /// Bar = 0b010,
624 /// Baz = 0b100
625 /// }
626 /// }
627 ///
628 /// let set0 = Flag::Foo | Flag::Bar;
629 /// let set1 = Flag::Baz | Flag::Bar;
630 /// assert_eq!(set0 ^ set1, Flag::Foo | Flag::Baz);
631 /// assert_eq!(set0 ^ Flag::Foo, Flag::Bar);
632 /// ```
633 #[inline]
634 fn bitxor(self, rhs: R) -> Self {
635 FlagSet(self.0 ^ rhs.into().0)
636 }
637}
638
639impl<F: Flags, R: Into<FlagSet<F>>> BitXorAssign<R> for FlagSet<F> {
640 /// Assigns the current set with the specified flags toggled.
641 ///
642 /// ```
643 /// use flagset::{FlagSet, flags};
644 ///
645 /// flags! {
646 /// enum Flag: u16 {
647 /// Foo = 0b001,
648 /// Bar = 0b010,
649 /// Baz = 0b100
650 /// }
651 /// }
652 ///
653 /// let mut set0 = Flag::Foo | Flag::Bar;
654 /// let mut set1 = Flag::Baz | Flag::Bar;
655 ///
656 /// set0 ^= set1;
657 /// assert_eq!(set0, Flag::Foo | Flag::Baz);
658 ///
659 /// set1 ^= Flag::Baz;
660 /// assert_eq!(set1, Flag::Bar);
661 /// ```
662 #[inline]
663 fn bitxor_assign(&mut self, rhs: R) {
664 self.0 ^= rhs.into().0
665 }
666}
667
668impl<F: Flags, R: Into<FlagSet<F>>> Sub<R> for FlagSet<F> {
669 type Output = Self;
670
671 /// Calculates set difference (the current set without the specified flags).
672 ///
673 /// ```
674 /// use flagset::{FlagSet, flags};
675 ///
676 /// flags! {
677 /// pub enum Flag: u8 {
678 /// Foo = 1,
679 /// Bar = 2,
680 /// Baz = 4
681 /// }
682 /// }
683 ///
684 /// let set0 = Flag::Foo | Flag::Bar;
685 /// let set1 = Flag::Baz | Flag::Bar;
686 /// assert_eq!(set0 - set1, Flag::Foo);
687 /// ```
688 #[inline]
689 fn sub(self, rhs: R) -> Self {
690 self & !rhs.into()
691 }
692}
693
694impl<F: Flags, R: Into<FlagSet<F>>> SubAssign<R> for FlagSet<F> {
695 /// Assigns set difference (the current set without the specified flags).
696 ///
697 /// ```
698 /// use flagset::{FlagSet, flags};
699 ///
700 /// flags! {
701 /// pub enum Flag: u8 {
702 /// Foo = 1,
703 /// Bar = 2,
704 /// Baz = 4
705 /// }
706 /// }
707 ///
708 /// let mut set0 = Flag::Foo | Flag::Bar;
709 /// set0 -= Flag::Baz | Flag::Bar;
710 /// assert_eq!(set0, Flag::Foo);
711 /// ```
712 #[inline]
713 fn sub_assign(&mut self, rhs: R) {
714 *self &= !rhs.into();
715 }
716}
717
718impl<F: Flags, R: Into<FlagSet<F>>> Rem<R> for FlagSet<F> {
719 type Output = Self;
720
721 /// Calculates the symmetric difference between two sets.
722 ///
723 /// The symmetric difference between two sets is the set of all flags
724 /// that appear in one set or the other, but not both.
725 ///
726 /// ```
727 /// use flagset::{FlagSet, flags};
728 ///
729 /// flags! {
730 /// pub enum Flag: u8 {
731 /// Foo = 1,
732 /// Bar = 2,
733 /// Baz = 4
734 /// }
735 /// }
736 ///
737 /// let set0 = Flag::Foo | Flag::Bar;
738 /// let set1 = Flag::Baz | Flag::Bar;
739 /// assert_eq!(set0 % set1, Flag::Foo | Flag::Baz);
740 /// ```
741 #[inline]
742 fn rem(self, rhs: R) -> Self {
743 let rhs = rhs.into();
744 (self - rhs) | (rhs - self)
745 }
746}
747
748impl<F: Flags, R: Into<FlagSet<F>>> RemAssign<R> for FlagSet<F> {
749 /// Assigns the symmetric difference between two sets.
750 ///
751 /// The symmetric difference between two sets is the set of all flags
752 /// that appear in one set or the other, but not both.
753 ///
754 /// ```
755 /// use flagset::{FlagSet, flags};
756 ///
757 /// flags! {
758 /// pub enum Flag: u8 {
759 /// Foo = 1,
760 /// Bar = 2,
761 /// Baz = 4
762 /// }
763 /// }
764 ///
765 /// let mut set0 = Flag::Foo | Flag::Bar;
766 /// let set1 = Flag::Baz | Flag::Bar;
767 /// set0 %= set1;
768 /// assert_eq!(set0, Flag::Foo | Flag::Baz);
769 /// ```
770 #[inline]
771 fn rem_assign(&mut self, rhs: R) {
772 *self = *self % rhs
773 }
774}
775
776impl<F: Flags, R: Into<FlagSet<F>>> Extend<R> for FlagSet<F> {
777 /// Add values by iterating over some collection.
778 ///
779 /// ```
780 /// use flagset::{FlagSet, flags};
781 ///
782 /// flags! {
783 /// pub enum Flag: u8 {
784 /// Foo = 1,
785 /// Bar = 2,
786 /// Baz = 4
787 /// }
788 /// }
789 ///
790 /// let flag_vec = vec![Flag::Bar, Flag::Baz];
791 /// let mut some_extended_flags = FlagSet::from(Flag::Foo);
792 /// some_extended_flags.extend(flag_vec);
793 /// assert_eq!(some_extended_flags, Flag::Foo | Flag::Bar | Flag::Baz);
794 /// ```
795 fn extend<T>(&mut self, iter: T)
796 where
797 T: IntoIterator<Item = R>,
798 {
799 for item in iter {
800 *self |= item;
801 }
802 }
803}
804
805impl<F: Flags> FlagSet<F> {
806 /// Creates a new set from bits; returning `Err(InvalidBits)` on invalid/unknown bits.
807 ///
808 /// ```
809 /// use flagset::{FlagSet, flags};
810 ///
811 /// flags! {
812 /// pub enum Flag: u16 {
813 /// Foo = 0b0001,
814 /// Bar = 0b0010,
815 /// Baz = 0b0100,
816 /// Qux = 0b1010, // Implies Bar
817 /// }
818 /// }
819 ///
820 /// assert_eq!(FlagSet::<Flag>::new(0b00101), Ok(Flag::Foo | Flag::Baz));
821 /// assert_eq!(FlagSet::<Flag>::new(0b01101), Err(flagset::InvalidBits)); // Invalid
822 /// assert_eq!(FlagSet::<Flag>::new(0b10101), Err(flagset::InvalidBits)); // Unknown
823 /// ```
824 #[inline]
825 pub fn new(bits: F::Type) -> core::result::Result<Self, InvalidBits> {
826 if Self::new_truncated(bits).0 == bits {
827 return Ok(FlagSet(bits));
828 }
829
830 Err(InvalidBits)
831 }
832
833 /// Creates a new set from bits; truncating invalid/unknown bits.
834 ///
835 /// ```
836 /// use flagset::{FlagSet, flags};
837 ///
838 /// flags! {
839 /// pub enum Flag: u16 {
840 /// Foo = 0b0001,
841 /// Bar = 0b0010,
842 /// Baz = 0b0100,
843 /// Qux = 0b1010, // Implies Bar
844 /// }
845 /// }
846 ///
847 /// let set = FlagSet::new_truncated(0b11101); // Has invalid and unknown.
848 /// assert_eq!(set, Flag::Foo | Flag::Baz);
849 /// assert_eq!(set.bits(), 0b00101); // Has neither.
850 /// ```
851 #[inline]
852 pub fn new_truncated(bits: F::Type) -> Self {
853 let mut set = Self::default();
854
855 for flag in FlagSet::<F>(bits) {
856 set |= flag;
857 }
858
859 set
860 }
861
862 /// Creates a new set from bits; use of invalid/unknown bits is undefined.
863 ///
864 /// ```
865 /// use flagset::{FlagSet, flags};
866 ///
867 /// flags! {
868 /// pub enum Flag: u16 {
869 /// Foo = 0b0001,
870 /// Bar = 0b0010,
871 /// Baz = 0b0100,
872 /// Qux = 0b1010, // Implies Bar
873 /// }
874 /// }
875 ///
876 /// // Unknown and invalid bits are retained. Behavior is undefined.
877 /// const set: FlagSet<Flag> = unsafe { FlagSet::<Flag>::new_unchecked(0b11101) };
878 /// assert_eq!(set.bits(), 0b11101);
879 /// ```
880 ///
881 /// # Safety
882 ///
883 /// This constructor doesn't check that the bits are valid. If you pass
884 /// undefined flags, undefined behavior may result.
885 #[inline]
886 pub const unsafe fn new_unchecked(bits: F::Type) -> Self {
887 FlagSet(bits)
888 }
889
890 /// Creates a new FlagSet containing all possible flags.
891 ///
892 /// ```
893 /// use flagset::{FlagSet, flags};
894 ///
895 /// flags! {
896 /// pub enum Flag: u8 {
897 /// Foo = 1,
898 /// Bar = 2,
899 /// Baz = 4
900 /// }
901 /// }
902 ///
903 /// let set = FlagSet::full();
904 /// assert!(!set.is_empty());
905 /// assert!(set.is_full());
906 /// assert!(set.contains(Flag::Foo));
907 /// assert!(set.contains(Flag::Bar));
908 /// assert!(set.contains(Flag::Baz));
909 /// ```
910 #[inline]
911 pub fn full() -> Self {
912 let mut set = Self::default();
913 for f in F::LIST {
914 set |= *f
915 }
916 set
917 }
918
919 /// Returns the raw bits of the set.
920 ///
921 /// ```
922 /// use flagset::{FlagSet, flags};
923 ///
924 /// flags! {
925 /// pub enum Flag: u16 {
926 /// Foo = 0b0001,
927 /// Bar = 0b0010,
928 /// Baz = 0b0100,
929 /// }
930 /// }
931 ///
932 /// let set = Flag::Foo | Flag::Baz;
933 /// assert_eq!(set.bits(), 0b0101u16);
934 /// ```
935 #[inline]
936 pub fn bits(self) -> F::Type {
937 self.0
938 }
939
940 /// Returns true if the FlagSet contains no flags.
941 ///
942 /// ```
943 /// use flagset::{FlagSet, flags};
944 ///
945 /// flags! {
946 /// pub enum Flag: u8 {
947 /// Foo = 1,
948 /// Bar = 2,
949 /// Baz = 4
950 /// }
951 /// }
952 ///
953 /// let mut set = Flag::Foo | Flag::Bar;
954 /// assert!(!set.is_empty());
955 ///
956 /// set &= Flag::Baz;
957 /// assert!(set.is_empty());
958 /// ```
959 #[inline]
960 pub fn is_empty(self) -> bool {
961 self == Self::default()
962 }
963
964 /// Returns true if the FlagSet contains all possible flags.
965 ///
966 /// ```
967 /// use flagset::{FlagSet, flags};
968 ///
969 /// flags! {
970 /// pub enum Flag: u8 {
971 /// Foo = 1,
972 /// Bar = 2,
973 /// Baz = 4
974 /// }
975 /// }
976 ///
977 /// let mut set = Flag::Foo | Flag::Bar;
978 /// assert!(!set.is_full());
979 ///
980 /// set |= Flag::Baz;
981 /// assert!(set.is_full());
982 /// ```
983 #[inline]
984 pub fn is_full(self) -> bool {
985 self == Self::full()
986 }
987
988 /// Returns true if the two `FlagSet`s do not share any flags.
989 ///
990 /// ```
991 /// use flagset::{FlagSet, flags};
992 ///
993 /// flags! {
994 /// pub enum Flag: u8 {
995 /// Foo = 1,
996 /// Bar = 2,
997 /// Baz = 4
998 /// }
999 /// }
1000 ///
1001 /// let set = Flag::Foo | Flag::Bar;
1002 /// assert!(!set.is_disjoint(Flag::Foo));
1003 /// assert!(!set.is_disjoint(Flag::Foo | Flag::Baz));
1004 /// assert!(set.is_disjoint(Flag::Baz));
1005 /// ```
1006 #[inline]
1007 pub fn is_disjoint(self, rhs: impl Into<FlagSet<F>>) -> bool {
1008 self & rhs == Self::default()
1009 }
1010
1011 /// Returns true if this FlagSet is a superset of the specified flags.
1012 ///
1013 /// ```
1014 /// use flagset::{FlagSet, flags};
1015 ///
1016 /// flags! {
1017 /// pub enum Flag: u8 {
1018 /// Foo = 1,
1019 /// Bar = 2,
1020 /// Baz = 4
1021 /// }
1022 /// }
1023 ///
1024 /// let set = Flag::Foo | Flag::Bar;
1025 /// assert!(set.contains(Flag::Foo));
1026 /// assert!(set.contains(Flag::Foo | Flag::Bar));
1027 /// assert!(!set.contains(Flag::Foo | Flag::Bar | Flag::Baz));
1028 /// ```
1029 #[inline]
1030 pub fn contains(self, rhs: impl Into<FlagSet<F>>) -> bool {
1031 let rhs = rhs.into();
1032 self & rhs == rhs
1033 }
1034
1035 /// Removes all flags from the FlagSet.
1036 ///
1037 /// ```
1038 /// use flagset::{FlagSet, flags};
1039 ///
1040 /// flags! {
1041 /// pub enum Flag: u8 {
1042 /// Foo = 1,
1043 /// Bar = 2,
1044 /// Baz = 4
1045 /// }
1046 /// }
1047 ///
1048 /// let mut set = Flag::Foo | Flag::Bar;
1049 /// assert!(!set.is_empty());
1050 ///
1051 /// set.clear();
1052 /// assert!(set.is_empty());
1053 /// ```
1054 #[inline]
1055 pub fn clear(&mut self) {
1056 *self = Self::default();
1057 }
1058
1059 /// Clears the current set and returns an iterator of all removed flags.
1060 ///
1061 /// ```
1062 /// use flagset::{FlagSet, flags};
1063 ///
1064 /// flags! {
1065 /// pub enum Flag: u8 {
1066 /// Foo = 1,
1067 /// Bar = 2,
1068 /// Baz = 4
1069 /// }
1070 /// }
1071 ///
1072 /// let mut set = Flag::Foo | Flag::Bar;
1073 /// let mut iter = set.drain();
1074 /// assert!(set.is_empty());
1075 /// assert_eq!(iter.next(), Some(Flag::Foo));
1076 /// assert_eq!(iter.next(), Some(Flag::Bar));
1077 /// assert_eq!(iter.next(), None);
1078 /// ```
1079 #[inline]
1080 pub fn drain(&mut self) -> Iter<F> {
1081 let iter = self.into_iter();
1082 *self = Self::default();
1083 iter
1084 }
1085
1086 /// Retain only the flags flags specified by the predicate.
1087 ///
1088 /// ```
1089 /// use flagset::{FlagSet, flags};
1090 ///
1091 /// flags! {
1092 /// pub enum Flag: u8 {
1093 /// Foo = 1,
1094 /// Bar = 2,
1095 /// Baz = 4
1096 /// }
1097 /// }
1098 ///
1099 /// let mut set0 = Flag::Foo | Flag::Bar;
1100 /// set0.retain(|f| f != Flag::Foo);
1101 /// assert_eq!(set0, Flag::Bar);
1102 /// ```
1103 #[inline]
1104 pub fn retain(&mut self, func: impl Fn(F) -> bool) {
1105 for f in self.into_iter() {
1106 if !func(f) {
1107 *self -= f
1108 }
1109 }
1110 }
1111}
1112
1113#[cfg(feature = "serde")]
1114impl<F: Flags> serde::Serialize for FlagSet<F>
1115where
1116 F::Type: serde::ser::Serialize,
1117{
1118 #[inline]
1119 fn serialize<S>(&self, serializer: S) -> core::result::Result<S::Ok, S::Error>
1120 where
1121 S: serde::ser::Serializer,
1122 {
1123 self.0.serialize(serializer)
1124 }
1125}
1126
1127#[cfg(feature = "serde")]
1128impl<'de, F: Flags> serde::Deserialize<'de> for FlagSet<F>
1129where
1130 F::Type: serde::de::Deserialize<'de>,
1131{
1132 #[inline]
1133 fn deserialize<D>(deserializer: D) -> core::result::Result<Self, D::Error>
1134 where
1135 D: serde::de::Deserializer<'de>,
1136 {
1137 Ok(FlagSet(F::Type::deserialize(deserializer)?))
1138 }
1139}
1140
1141/// Define flag value using the `enum` syntax. See below for details.
1142///
1143/// Each enumeration value **MUST** have a specified value.
1144///
1145/// The width of the bitfield **MUST** also be specified by its integer type.
1146///
1147/// It is important to note that the size of the flag enumeration itself is
1148/// unrelated to the size of the corresponding `FlagSet` instance.
1149///
1150/// It is also worth noting that this macro automatically implements a variety
1151/// of standard traits including:
1152/// * Copy
1153/// * Clone
1154/// * Debug
1155/// * PartialEq
1156/// * Eq
1157/// * From<$enum> for $integer
1158/// * Not
1159/// * BitAnd
1160/// * BitOr
1161/// * BitXor
1162/// * Sub
1163/// * Rem
1164///
1165/// ```
1166/// use std::mem::{align_of, size_of};
1167/// use flagset::{FlagSet, flags};
1168///
1169/// flags! {
1170/// enum FlagEmpty: u32 {}
1171///
1172/// enum Flag8: u8 {
1173/// Foo = 0b001,
1174/// Bar = 0b010,
1175/// Baz = 0b100
1176/// }
1177///
1178/// pub enum Flag16: u16 {
1179/// Foo,
1180/// Bar,
1181/// #[deprecated]
1182/// Baz,
1183/// }
1184///
1185/// #[derive(PartialOrd, Ord)]
1186/// enum Flag32: u32 {
1187/// Foo = 0b001,
1188/// #[deprecated]
1189/// Bar = 0b010,
1190/// Baz = 0b100
1191/// }
1192///
1193/// #[repr(u64)]
1194/// enum Flag64: u64 {
1195/// Foo = 0b001,
1196/// Bar = 0b010,
1197/// Baz = 0b100
1198/// }
1199///
1200/// #[repr(u32)]
1201/// enum Flag128: u128 {
1202/// Foo = 0b001,
1203/// Bar = 0b010,
1204/// Baz = 0b100
1205/// }
1206/// }
1207///
1208/// assert_eq!(size_of::<Flag8>(), 1);
1209/// assert_eq!(size_of::<Flag16>(), 1);
1210/// assert_eq!(size_of::<Flag32>(), 1);
1211/// assert_eq!(size_of::<Flag64>(), 8);
1212/// assert_eq!(size_of::<Flag128>(), 4);
1213///
1214/// assert_eq!(align_of::<Flag8>(), 1);
1215/// assert_eq!(align_of::<Flag16>(), 1);
1216/// assert_eq!(align_of::<Flag32>(), 1);
1217/// assert_eq!(align_of::<Flag64>(), align_of::<u64>());
1218/// assert_eq!(align_of::<Flag128>(), align_of::<u32>());
1219///
1220/// assert_eq!(size_of::<FlagSet<Flag8>>(), size_of::<u8>());
1221/// assert_eq!(size_of::<FlagSet<Flag16>>(), size_of::<u16>());
1222/// assert_eq!(size_of::<FlagSet<Flag32>>(), size_of::<u32>());
1223/// assert_eq!(size_of::<FlagSet<Flag64>>(), size_of::<u64>());
1224/// assert_eq!(size_of::<FlagSet<Flag128>>(), size_of::<u128>());
1225///
1226/// assert_eq!(align_of::<FlagSet<Flag8>>(), align_of::<u8>());
1227/// assert_eq!(align_of::<FlagSet<Flag16>>(), align_of::<u16>());
1228/// assert_eq!(align_of::<FlagSet<Flag32>>(), align_of::<u32>());
1229/// assert_eq!(align_of::<FlagSet<Flag64>>(), align_of::<u64>());
1230/// assert_eq!(align_of::<FlagSet<Flag128>>(), align_of::<u128>());
1231/// ```
1232#[macro_export]
1233macro_rules! flags {
1234 () => {};
1235
1236 // Entry point for enumerations without values.
1237 ($(#[$m:meta])* $p:vis enum $n:ident: $t:ty { $($(#[$a:meta])* $k:ident),+ $(,)* } $($next:tt)*) => {
1238 $crate::flags! { $(#[$m])* $p enum $n: $t { $($(#[$a])* $k = (1 << $n::$k as $t)),+ } $($next)* }
1239 };
1240
1241 // Entrypoint for enumerations with values.
1242 ($(#[$m:meta])* $p:vis enum $n:ident: $t:ty { $($(#[$a:meta])*$k:ident = $v:expr),* $(,)* } $($next:tt)*) => {
1243 $(#[$m])*
1244 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
1245 $p enum $n { $($(#[$a])* $k),* }
1246
1247 impl $crate::Flags for $n {
1248 type Type = $t;
1249
1250 const LIST: &'static [Self] = &[$($n::$k),*];
1251 }
1252
1253 impl ::core::convert::From<$n> for $crate::FlagSet<$n> {
1254 #[inline]
1255 fn from(value: $n) -> Self {
1256 unsafe {
1257 match value {
1258 $($n::$k => Self::new_unchecked($v)),*
1259 }
1260 }
1261 }
1262 }
1263
1264 impl ::core::ops::Not for $n {
1265 type Output = $crate::FlagSet<$n>;
1266
1267 #[inline]
1268 fn not(self) -> Self::Output {
1269 !$crate::FlagSet::from(self)
1270 }
1271 }
1272
1273 impl<R: ::core::convert::Into<$crate::FlagSet<$n>>> ::core::ops::BitAnd<R> for $n {
1274 type Output = $crate::FlagSet<$n>;
1275
1276 #[inline]
1277 fn bitand(self, rhs: R) -> Self::Output {
1278 $crate::FlagSet::from(self) & rhs
1279 }
1280 }
1281
1282 impl<R: ::core::convert::Into<$crate::FlagSet<$n>>> ::core::ops::BitOr<R> for $n {
1283 type Output = $crate::FlagSet<$n>;
1284
1285 #[inline]
1286 fn bitor(self, rhs: R) -> Self::Output {
1287 $crate::FlagSet::from(self) | rhs
1288 }
1289 }
1290
1291 impl<R: ::core::convert::Into<$crate::FlagSet<$n>>> ::core::ops::BitXor<R> for $n {
1292 type Output = $crate::FlagSet<$n>;
1293
1294 #[inline]
1295 fn bitxor(self, rhs: R) -> Self::Output {
1296 $crate::FlagSet::from(self) ^ rhs
1297 }
1298 }
1299
1300 impl<R: ::core::convert::Into<$crate::FlagSet<$n>>> ::core::ops::Sub<R> for $n {
1301 type Output = $crate::FlagSet<$n>;
1302
1303 #[inline]
1304 fn sub(self, rhs: R) -> Self::Output {
1305 $crate::FlagSet::from(self) - rhs
1306 }
1307 }
1308
1309 impl<R: ::core::convert::Into<$crate::FlagSet<$n>>> ::core::ops::Rem<R> for $n {
1310 type Output = $crate::FlagSet<$n>;
1311
1312 #[inline]
1313 fn rem(self, rhs: R) -> Self::Output {
1314 $crate::FlagSet::from(self) % rhs
1315 }
1316 }
1317
1318 $crate::flags! { $($next)* }
1319 };
1320}