// // Copyright 2019 Red Hat, Inc. // // Author: Nathaniel McCallum <npmccallum@redhat.com> // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. //
//! # Welcome to FlagSet! //! //! FlagSet is a new, ergonomic approach to handling flags that combines the //! best of existing crates like `bitflags` and `enumflags` without their //! downsides. //! //! ## Existing Implementations //! //! The `bitflags` crate has long been part of the Rust ecosystem. //! Unfortunately, it doesn't feel like natural Rust. The `bitflags` crate //! uses a wierd struct format to define flags. Flags themselves are just //! integers constants, so there is little type-safety involved. But it doesn't //! have any dependencies. It also allows you to define implied flags (otherwise //! known as overlapping flags). //! //! The `enumflags` crate tried to improve on `bitflags` by using enumerations //! to define flags. This was a big improvement to the natural feel of the code. //! Unfortunately, there are some design flaws. To generate the flags, //! procedural macros were used. This implied two separate crates plus //! additional dependencies. Further, `enumflags` specifies the size of the //! flags using a `repr($size)` attribute. Unfortunately, this attribute //! cannot resolve type aliases, such as `c_int`. This makes `enumflags` a //! poor fit for FFI, which is the most important place for a flags library. //! The `enumflags` crate also disallows overlapping flags and is not //! maintained. //! //! FlagSet improves on both of these by adopting the `enumflags` natural feel //! and the `bitflags` mode of flag generation; as well as additional API usage //! niceties. FlagSet has no dependencies and is extensively documented and //! tested. It also tries very hard to prevent you from making mistakes by //! avoiding external usage of the integer types. FlagSet is also a zero-cost //! abstraction: all functions are inlineable and should reduce to the core //! integer operations. FlagSet also does not depend on stdlib, so it can be //! used in `no_std` libraries and applications. //! //! ## Defining Flags //! //! Flags are defined using the `flags!` macro: //! //! ``` //! use flagset::{FlagSet, flags}; //! use std::os::raw::c_int; //! //! flags! { //! enum FlagsA: u8 { //! Foo, //! Bar, //! Baz, //! } //! //! enum FlagsB: c_int { //! Foo, //! Bar, //! Baz, //! } //! } //! ``` //! //! Notice that a flag definition looks just like a regular enumeration, with //! the addition of the field-size type. The field-size type is required and //! can be either a type or a type alias. Both examples are given above. //! //! Also note that the field-size type specifies the size of the corresponding //! `FlagSet` type, not size of the enumeration itself. To specify the size of //! the enumeration, use the `repr($size)` attribute as specified below. //! //! ## Flag Values //! //! Flags often need values assigned to them. This can be done implicitly, //! where the value depends on the order of the flags: //! //! ``` //! use flagset::{FlagSet, flags}; //! //! flags! { //! enum Flags: u16 { //! Foo, // Implicit Value: 0b0001 //! Bar, // Implicit Value: 0b0010 //! Baz, // Implicit Value: 0b0100 //! } //! } //! ``` //! //! Alternatively, flag values can be defined explicitly, by specifying any //! `const` expression: //! //! ``` //! use flagset::{FlagSet, flags}; //! //! flags! { //! enum Flags: u16 { //! Foo = 0x01, // Explicit Value: 0b0001 //! Bar = 2, // Explicit Value: 0b0010 //! Baz = 0b0100, // Explicit Value: 0b0100 //! } //! } //! ``` //! //! Flags can also overlap or "imply" other flags: //! //! ``` //! use flagset::{FlagSet, flags}; //! //! flags! { //! enum Flags: u16 { //! Foo = 0b0001, //! Bar = 0b0010, //! Baz = 0b0110, // Implies Bar //! All = (Flags::Foo | Flags::Bar | Flags::Baz).bits(), //! } //! } //! ``` //! //! ## Specifying Attributes //! //! Attributes can be used on the enumeration itself or any of the values: //! //! ``` //! use flagset::{FlagSet, flags}; //! //! flags! { //! #[derive(PartialOrd, Ord)] //! enum Flags: u8 { //! Foo, //! #[deprecated] //! Bar, //! Baz, //! } //! } //! ``` //! //! ## Collections of Flags //! //! A collection of flags is a `FlagSet<T>`. If you are storing the flags in //! memory, the raw `FlagSet<T>` type should be used. However, if you want to //! receive flags as an input to a function, you should use //! `impl Into<FlagSet<T>>`. This allows for very ergonomic APIs: //! //! ``` //! use flagset::{FlagSet, flags}; //! //! flags! { //! enum Flags: u8 { //! Foo, //! Bar, //! Baz, //! } //! } //! //! struct Container(FlagSet<Flags>); //! //! impl Container { //! fn new(flags: impl Into<FlagSet<Flags>>) -> Container { //! Container(flags.into()) //! } //! } //! //! assert_eq!(Container::new(Flags::Foo | Flags::Bar).0.bits(), 0b011); //! assert_eq!(Container::new(Flags::Foo).0.bits(), 0b001); //! assert_eq!(Container::new(None).0.bits(), 0b000); //! ``` //! //! ## Operations //! //! Operations can be performed on a `FlagSet<F>` or on individual flags: //! //! | Operator | Assignment Operator | Meaning | //! |----------|---------------------|------------------------| //! | \| | \|= | Union | //! | & | &= | Intersection | //! | ^ | ^= | Toggle specified flags | //! | - | -= | Difference | //! | % | %= | Symmetric difference | //! | ! | | Toggle all flags | //! #![cfg_attr(
feature = "serde",
doc = r#"
## Optional Serde support
[Serde] support can be enabled with the 'serde' feature flag. You can then serialize and
deserialize `FlagSet<T>` to and from any of the [supported formats]:
``` use flagset::{FlagSet, flags};
flags! { enum Flags: u8 {
Foo,
Bar,
}
}
let flagset = Flags::Foo | Flags::Bar; let json = serde_json::to_string(&flagset).unwrap(); let flagset: FlagSet<Flags> = serde_json::from_str(&json).unwrap();
assert_eq!(flagset.bits(), 0b011);
```
For serialization and deserialization of flags enum itself, you can use the [`serde_repr`] crate
(or implement `serde::ser::Serialize` and `serde:de::Deserialize` manually), combined with the
appropriate `repr` attribute:
``` use flagset::{FlagSet, flags}; use serde_repr::{Serialize_repr, Deserialize_repr};
impl<F: Flags> Not for FlagSet<F> { type Output = Self;
/// Calculates the complement of the current set. /// /// In common parlance, this returns the set of all possible flags that are /// not in the current set. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// #[derive(PartialOrd, Ord)] /// enum Flag: u8 { /// Foo = 1 << 0, /// Bar = 1 << 1, /// Baz = 1 << 2 /// } /// } /// /// let set = !FlagSet::from(Flag::Foo); /// assert!(!set.is_empty()); /// assert!(!set.is_full()); /// assert!(!set.contains(Flag::Foo)); /// assert!(set.contains(Flag::Bar)); /// assert!(set.contains(Flag::Baz)); /// ``` #[inline] fn not(self) -> Self {
FlagSet(!self.0)
}
}
impl<F: Flags, R: Into<FlagSet<F>>> BitAnd<R> for FlagSet<F> { type Output = Self;
/// Calculates the intersection of the current set and the specified flags. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// #[derive(PartialOrd, Ord)] /// pub enum Flag: u8 { /// Foo = 0b001, /// Bar = 0b010, /// Baz = 0b100 /// } /// } /// /// let set0 = Flag::Foo | Flag::Bar; /// let set1 = Flag::Baz | Flag::Bar; /// assert_eq!(set0 & set1, Flag::Bar); /// assert_eq!(set0 & Flag::Foo, Flag::Foo); /// assert_eq!(set1 & Flag::Baz, Flag::Baz); /// ``` #[inline] fn bitand(self, rhs: R) -> Self {
FlagSet(self.0 & rhs.into().0)
}
}
impl<F: Flags, R: Into<FlagSet<F>>> BitAndAssign<R> for FlagSet<F> { /// Assigns the intersection of the current set and the specified flags. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// enum Flag: u64 { /// Foo = 0b001, /// Bar = 0b010, /// Baz = 0b100 /// } /// } /// /// let mut set0 = Flag::Foo | Flag::Bar; /// let mut set1 = Flag::Baz | Flag::Bar; /// /// set0 &= set1; /// assert_eq!(set0, Flag::Bar); /// /// set1 &= Flag::Baz; /// assert_eq!(set0, Flag::Bar); /// ``` #[inline] fn bitand_assign(&mutself, rhs: R) { self.0 &= rhs.into().0
}
}
impl<F: Flags, R: Into<FlagSet<F>>> BitOr<R> for FlagSet<F> { type Output = Self;
/// Calculates the union of the current set with the specified flags. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// #[derive(PartialOrd, Ord)] /// pub enum Flag: u8 { /// Foo = 0b001, /// Bar = 0b010, /// Baz = 0b100 /// } /// } /// /// let set0 = Flag::Foo | Flag::Bar; /// let set1 = Flag::Baz | Flag::Bar; /// assert_eq!(set0 | set1, FlagSet::full()); /// ``` #[inline] fn bitor(self, rhs: R) -> Self {
FlagSet(self.0 | rhs.into().0)
}
}
impl<F: Flags, R: Into<FlagSet<F>>> BitOrAssign<R> for FlagSet<F> { /// Assigns the union of the current set with the specified flags. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// enum Flag: u64 { /// Foo = 0b001, /// Bar = 0b010, /// Baz = 0b100 /// } /// } /// /// let mut set0 = Flag::Foo | Flag::Bar; /// let mut set1 = Flag::Bar | Flag::Baz; /// /// set0 |= set1; /// assert_eq!(set0, FlagSet::full()); /// /// set1 |= Flag::Baz; /// assert_eq!(set1, Flag::Bar | Flag::Baz); /// ``` #[inline] fn bitor_assign(&mutself, rhs: R) { self.0 |= rhs.into().0
}
}
impl<F: Flags, R: Into<FlagSet<F>>> BitXor<R> for FlagSet<F> { type Output = Self;
/// Calculates the current set with the specified flags toggled. /// /// This is commonly known as toggling the presence /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// enum Flag: u32 { /// Foo = 0b001, /// Bar = 0b010, /// Baz = 0b100 /// } /// } /// /// let set0 = Flag::Foo | Flag::Bar; /// let set1 = Flag::Baz | Flag::Bar; /// assert_eq!(set0 ^ set1, Flag::Foo | Flag::Baz); /// assert_eq!(set0 ^ Flag::Foo, Flag::Bar); /// ``` #[inline] fn bitxor(self, rhs: R) -> Self {
FlagSet(self.0 ^ rhs.into().0)
}
}
impl<F: Flags, R: Into<FlagSet<F>>> BitXorAssign<R> for FlagSet<F> { /// Assigns the current set with the specified flags toggled. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// enum Flag: u16 { /// Foo = 0b001, /// Bar = 0b010, /// Baz = 0b100 /// } /// } /// /// let mut set0 = Flag::Foo | Flag::Bar; /// let mut set1 = Flag::Baz | Flag::Bar; /// /// set0 ^= set1; /// assert_eq!(set0, Flag::Foo | Flag::Baz); /// /// set1 ^= Flag::Baz; /// assert_eq!(set1, Flag::Bar); /// ``` #[inline] fn bitxor_assign(&mutself, rhs: R) { self.0 ^= rhs.into().0
}
}
impl<F: Flags, R: Into<FlagSet<F>>> Sub<R> for FlagSet<F> { type Output = Self;
/// Calculates set difference (the current set without the specified flags). /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u8 { /// Foo = 1, /// Bar = 2, /// Baz = 4 /// } /// } /// /// let set0 = Flag::Foo | Flag::Bar; /// let set1 = Flag::Baz | Flag::Bar; /// assert_eq!(set0 - set1, Flag::Foo); /// ``` #[inline] fn sub(self, rhs: R) -> Self { self & !rhs.into()
}
}
impl<F: Flags, R: Into<FlagSet<F>>> SubAssign<R> for FlagSet<F> { /// Assigns set difference (the current set without the specified flags). /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u8 { /// Foo = 1, /// Bar = 2, /// Baz = 4 /// } /// } /// /// let mut set0 = Flag::Foo | Flag::Bar; /// set0 -= Flag::Baz | Flag::Bar; /// assert_eq!(set0, Flag::Foo); /// ``` #[inline] fn sub_assign(&mutself, rhs: R) {
*self &= !rhs.into();
}
}
impl<F: Flags, R: Into<FlagSet<F>>> Rem<R> for FlagSet<F> { type Output = Self;
/// Calculates the symmetric difference between two sets. /// /// The symmetric difference between two sets is the set of all flags /// that appear in one set or the other, but not both. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u8 { /// Foo = 1, /// Bar = 2, /// Baz = 4 /// } /// } /// /// let set0 = Flag::Foo | Flag::Bar; /// let set1 = Flag::Baz | Flag::Bar; /// assert_eq!(set0 % set1, Flag::Foo | Flag::Baz); /// ``` #[inline] fn rem(self, rhs: R) -> Self { let rhs = rhs.into();
(self - rhs) | (rhs - self)
}
}
impl<F: Flags, R: Into<FlagSet<F>>> RemAssign<R> for FlagSet<F> { /// Assigns the symmetric difference between two sets. /// /// The symmetric difference between two sets is the set of all flags /// that appear in one set or the other, but not both. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u8 { /// Foo = 1, /// Bar = 2, /// Baz = 4 /// } /// } /// /// let mut set0 = Flag::Foo | Flag::Bar; /// let set1 = Flag::Baz | Flag::Bar; /// set0 %= set1; /// assert_eq!(set0, Flag::Foo | Flag::Baz); /// ``` #[inline] fn rem_assign(&mutself, rhs: R) {
*self = *self % rhs
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.