flagset-0.4.3/.cargo_vcs_info.json0000644000000001360000000000100124650ustar { "git": { "sha1": "1d19565ea9437b939d55cebe7b4f031b29ed2837" }, "path_in_vcs": "" }flagset-0.4.3/.github/CODEOWNERS000064400000000000000000000004750072674642500142460ustar 00000000000000# This is a comment. # Each line is a file pattern followed by one or more owners. # These owners will be the default owners for everything in # the repo. Unless a later match takes precedence, # @global-owner1 and @global-owner2 will be requested for # review when someone opens a pull request. * @npmccallum flagset-0.4.3/.github/dependabot.yml000064400000000000000000000001440072674642500154740ustar 00000000000000version: 2 updates: - package-ecosystem: "cargo" directory: "/" schedule: interval: "daily" flagset-0.4.3/.github/workflows/enarxbot.yml000064400000000000000000000022240072674642500172470ustar 00000000000000name: enarxbot on: check_run: check_suite: create: delete: deployment: deployment_status: fork: gollum: issue_comment: issues: label: milestone: page_build: project: project_card: project_column: public: pull_request_target: types: - assigned - unassigned - labeled - unlabeled - opened - edited - closed - reopened - synchronize - ready_for_review - locked - unlocked - review_requested - review_request_removed push: registry_package: release: status: watch: schedule: - cron: '*/15 * * * *' workflow_dispatch: jobs: enarxbot: runs-on: ubuntu-latest env: BOT_TOKEN: ${{ secrets.BOT_TOKEN }} name: enarxbot steps: - uses: enarx/bot@master pull-request-responsibility: runs-on: ubuntu-latest env: BOT_TOKEN: ${{ secrets.BOT_TOKEN }} name: pull-request-responsibility steps: - uses: actions-automation/pull-request-responsibility@main with: actions: "request,assign,copy-labels-linked,merge" reviewers: "reviews" num_to_request: 3 flagset-0.4.3/.github/workflows/lint.yml000064400000000000000000000014150072674642500163740ustar 00000000000000on: [push, pull_request] name: lint jobs: fmt: name: cargo fmt runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: components: rustfmt toolchain: nightly profile: minimal override: true - uses: actions-rs/cargo@v1 with: command: fmt args: --all -- --check clippy: name: cargo clippy runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: components: clippy toolchain: nightly profile: minimal override: true - uses: actions-rs/cargo@v1 with: command: clippy args: -- -D warnings flagset-0.4.3/.github/workflows/test.yml000064400000000000000000000012260072674642500164050ustar 00000000000000on: [push, pull_request] name: test jobs: test: name: ${{ matrix.toolchain }} (${{ matrix.profile.name }}) runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - uses: actions-rs/toolchain@v1 with: toolchain: ${{ matrix.toolchain }} override: true - uses: actions-rs/cargo@v1 with: command: test args: ${{ matrix.profile.flag }} strategy: fail-fast: false matrix: toolchain: - nightly - beta - stable - 1.36.0 profile: - name: debug - name: release flag: --release flagset-0.4.3/.gitignore000064400000000000000000000000350072674642500132730ustar 00000000000000/target **/*.rs.bk Cargo.lockflagset-0.4.3/Cargo.toml0000644000000021430000000000100104630ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "flagset" version = "0.4.3" authors = ["Nathaniel McCallum "] description = "Data types and a macro for generating enumeration-based bit flags" homepage = "https://github.com/enarx/flagset" documentation = "https://docs.rs/flagset" readme = "README.md" keywords = ["flags", "bitflags", "enum", "enumflags"] license = "Apache-2.0" repository = "https://github.com/enarx/flagset" [package.metadata.docs.rs] all-features = true [dependencies.serde] version = "1.0" features = ["serde_derive"] optional = true [dev-dependencies.serde_json] version = "1.0" [dev-dependencies.serde_repr] version = "0.1" flagset-0.4.3/Cargo.toml.orig000064400000000000000000000012260072674642500141750ustar 00000000000000[package] name = "flagset" version = "0.4.3" authors = ["Nathaniel McCallum "] edition = "2018" license = "Apache-2.0" keywords = ["flags", "bitflags", "enum", "enumflags"] readme = "README.md" repository = "https://github.com/enarx/flagset" homepage = "https://github.com/enarx/flagset" documentation = "https://docs.rs/flagset" description = "Data types and a macro for generating enumeration-based bit flags" [dependencies.serde] version = "1.0" optional = true features = [ "serde_derive" ] [dev-dependencies.serde_json] version = "1.0" [dev-dependencies.serde_repr] version = "0.1" [package.metadata.docs.rs] all-features = true flagset-0.4.3/LICENSE000064400000000000000000000261360072674642500123220ustar 00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. flagset-0.4.3/README.md000064400000000000000000000150560072674642500125730ustar 00000000000000[![Build Status](https://github.com/enarx/flagset/workflows/test/badge.svg)](https://github.com/enarx/flagset/actions) ![Rust Version 1.36+](https://img.shields.io/badge/rustc-v1.36%2B-blue.svg) [![Crate](https://img.shields.io/crates/v/flagset.svg)](https://crates.io/crates/flagset) [![Docs](https://docs.rs/flagset/badge.svg)](https://docs.rs/flagset) ![License](https://img.shields.io/crates/l/flagset.svg?style=popout) # 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: ```rust 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: ```rust 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: ```rust 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: ```rust 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: ```rust 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`. If you are storing the flags in memory, the raw `FlagSet` type should be used. However, if you want to receive flags as an input to a function, you should use `impl Into>`. This allows for very ergonomic APIs: ```rust use flagset::{FlagSet, flags}; flags! { enum Flags: u8 { Foo, Bar, Baz, } } struct Container(FlagSet); impl Container { fn new(flags: impl Into>) -> 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` or on individual flags: | Operator | Assignment Operator | Meaning | |----------|---------------------|------------------------| | \| | \|= | Union | | & | &= | Intersection | | ^ | ^= | Toggle specified flags | | - | -= | Difference | | % | %= | Symmetric difference | | ! | | Toggle all flags | ## Optional Serde support [Serde] support can be enabled with the 'serde' feature flag. You can then serialize and deserialize `FlagSet` to and from any of the [supported formats]: ```rust 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 = 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: ```rust use flagset::{FlagSet, flags}; use serde_repr::{Serialize_repr, Deserialize_repr}; flags! { #[repr(u8)] #[derive(Deserialize_repr, Serialize_repr)] enum Flags: u8 { Foo, Bar, } } let json = serde_json::to_string(&Flags::Foo).unwrap(); let flag: Flags = serde_json::from_str(&json).unwrap(); assert_eq!(flag, Flags::Foo); ``` [Serde]: https://serde.rs/ [supported formats]: https://serde.rs/#data-formats [`serde_repr`]: https://crates.io/crates/serde_repr flagset-0.4.3/src/lib.rs000064400000000000000000001033530072674642500132150ustar 00000000000000// // Copyright 2019 Red Hat, Inc. // // Author: Nathaniel McCallum // // 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`. If you are storing the flags in //! memory, the raw `FlagSet` type should be used. However, if you want to //! receive flags as an input to a function, you should use //! `impl Into>`. This allows for very ergonomic APIs: //! //! ``` //! use flagset::{FlagSet, flags}; //! //! flags! { //! enum Flags: u8 { //! Foo, //! Bar, //! Baz, //! } //! } //! //! struct Container(FlagSet); //! //! impl Container { //! fn new(flags: impl Into>) -> 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` 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` 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 = 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}; flags! { #[repr(u8)] #[derive(Deserialize_repr, Serialize_repr)] enum Flags: u8 { Foo, Bar, } } let json = serde_json::to_string(&Flags::Foo).unwrap(); let flag: Flags = serde_json::from_str(&json).unwrap(); assert_eq!(flag, Flags::Foo); ``` [Serde]: https://serde.rs/ [supported formats]: https://serde.rs/#data-formats [`serde_repr`]: https://crates.io/crates/serde_repr "# )] #![allow(unknown_lints)] #![warn(clippy::all)] #![no_std] use core::fmt::{Debug, Formatter, Result}; use core::ops::*; /// Error type returned when creating a new flagset from bits is invalid or undefined. /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u16 { /// Foo = 0b0001, /// Bar = 0b0010, /// Baz = 0b0100, /// Qux = 0b1010, // Implies Bar /// } /// } /// /// assert_eq!(FlagSet::::new(0b01101), Err(flagset::InvalidBits)); // Invalid /// assert_eq!(FlagSet::::new(0b10101), Err(flagset::InvalidBits)); // Unknown /// ``` #[derive(Clone, Copy, Debug, Eq, PartialEq)] pub struct InvalidBits; impl core::fmt::Display for InvalidBits { #[inline] fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { write!(f, "invalid bits") } } #[doc(hidden)] pub trait Flags: Copy + Clone + Debug + PartialEq + Eq + BitAnd> + BitOr> + BitXor> + Sub> + Rem> + Not> + Into> + 'static { type Type: Copy + Clone + Debug + PartialEq + Eq + Default + BitAnd + BitAndAssign + BitOr + BitOrAssign + BitXor + BitXorAssign + Not; /// A slice containing all the possible flag values. const LIST: &'static [Self]; /// Creates an empty `FlagSet` of this type #[inline] fn none() -> FlagSet { FlagSet::default() } } #[derive(Copy, Clone, Eq)] pub struct FlagSet(F::Type); #[doc(hidden)] #[derive(Copy, Clone)] pub struct Iter(FlagSet, usize); impl Iterator for Iter { type Item = F; #[inline] fn next(&mut self) -> Option { while self.1 < F::LIST.len() { let next = F::LIST[self.1]; self.1 += 1; if self.0.contains(next) { return Some(next); } } None } } impl IntoIterator for FlagSet { type Item = F; type IntoIter = Iter; /// Iterate over the flags in the set. /// /// **NOTE**: The order in which the flags are iterated is undefined. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// enum Flag: u8 { /// Foo = 0b001, /// Bar = 0b010, /// Baz = 0b100 /// } /// } /// /// let set = Flag::Foo | Flag::Bar; /// let mut iter = set.into_iter(); /// assert_eq!(iter.next(), Some(Flag::Foo)); /// assert_eq!(iter.next(), Some(Flag::Bar)); /// assert_eq!(iter.next(), None); /// ``` #[inline] fn into_iter(self) -> Self::IntoIter { Iter(self, 0) } } impl Debug for FlagSet { #[inline] fn fmt(&self, f: &mut Formatter) -> Result { write!(f, "FlagSet(")?; for (i, flag) in self.into_iter().enumerate() { write!(f, "{}{:?}", if i > 0 { " | " } else { "" }, flag)?; } write!(f, ")") } } impl>> PartialEq for FlagSet { #[inline] fn eq(&self, rhs: &R) -> bool { self.0 == (*rhs).into().0 } } impl AsRef for FlagSet { #[inline] fn as_ref(&self) -> &F::Type { &self.0 } } impl From>> for FlagSet { /// Converts from `Option>` to `FlagSet`. /// /// Most notably, this allows for the use of `None` in many places to /// substitute for manually creating an empty `FlagSet`. See below. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// enum Flag: u8 { /// Foo = 0b001, /// Bar = 0b010, /// Baz = 0b100 /// } /// } /// /// fn convert(v: impl Into>) -> u8 { /// v.into().bits() /// } /// /// assert_eq!(convert(Flag::Foo | Flag::Bar), 0b011); /// assert_eq!(convert(Flag::Foo), 0b001); /// assert_eq!(convert(None), 0b000); /// ``` #[inline] fn from(value: Option>) -> FlagSet { value.unwrap_or_default() } } impl Default for FlagSet { /// Creates a new, empty FlagSet. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// enum Flag: u8 { /// Foo = 0b001, /// Bar = 0b010, /// Baz = 0b100 /// } /// } /// /// let set = FlagSet::::default(); /// 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 default() -> Self { FlagSet(F::Type::default()) } } impl Not for FlagSet { 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>> BitAnd for FlagSet { 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>> BitAndAssign for FlagSet { /// 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(&mut self, rhs: R) { self.0 &= rhs.into().0 } } impl>> BitOr for FlagSet { 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>> BitOrAssign for FlagSet { /// 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(&mut self, rhs: R) { self.0 |= rhs.into().0 } } impl>> BitXor for FlagSet { 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>> BitXorAssign for FlagSet { /// 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(&mut self, rhs: R) { self.0 ^= rhs.into().0 } } impl>> Sub for FlagSet { 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>> SubAssign for FlagSet { /// 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(&mut self, rhs: R) { *self &= !rhs.into(); } } impl>> Rem for FlagSet { 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>> RemAssign for FlagSet { /// 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(&mut self, rhs: R) { *self = *self % rhs } } impl FlagSet { /// Creates a new set from bits; returning `Err(InvalidBits)` on invalid/unknown bits. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u16 { /// Foo = 0b0001, /// Bar = 0b0010, /// Baz = 0b0100, /// Qux = 0b1010, // Implies Bar /// } /// } /// /// assert_eq!(FlagSet::::new(0b00101), Ok(Flag::Foo | Flag::Baz)); /// assert_eq!(FlagSet::::new(0b01101), Err(flagset::InvalidBits)); // Invalid /// assert_eq!(FlagSet::::new(0b10101), Err(flagset::InvalidBits)); // Unknown /// ``` #[inline] pub fn new(bits: F::Type) -> core::result::Result { if Self::new_truncated(bits).0 == bits { return Ok(FlagSet(bits)); } Err(InvalidBits) } /// Creates a new set from bits; truncating invalid/unknown bits. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u16 { /// Foo = 0b0001, /// Bar = 0b0010, /// Baz = 0b0100, /// Qux = 0b1010, // Implies Bar /// } /// } /// /// let set = FlagSet::new_truncated(0b11101); // Has invalid and unknown. /// assert_eq!(set, Flag::Foo | Flag::Baz); /// assert_eq!(set.bits(), 0b00101); // Has neither. /// ``` #[inline] pub fn new_truncated(bits: F::Type) -> Self { let mut set = Self::default(); for flag in FlagSet::(bits) { set |= flag; } set } /// Creates a new set from bits; use of invalid/unknown bits is undefined. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u16 { /// Foo = 0b0001, /// Bar = 0b0010, /// Baz = 0b0100, /// Qux = 0b1010, // Implies Bar /// } /// } /// /// // Unknown and invalid bits are retained. Behavior is undefined. /// let set = unsafe { FlagSet::::new_unchecked(0b11101) }; /// assert_eq!(set.bits(), 0b11101); /// ``` /// /// # Safety /// /// This constructor doesn't check that the bits are valid. If you pass /// undefined flags, undefined behavior may result. #[inline] pub unsafe fn new_unchecked(bits: F::Type) -> Self { FlagSet(bits) } /// Creates a new FlagSet containing all possible flags. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u8 { /// Foo = 1, /// Bar = 2, /// Baz = 4 /// } /// } /// /// let set = FlagSet::full(); /// assert!(!set.is_empty()); /// assert!(set.is_full()); /// assert!(set.contains(Flag::Foo)); /// assert!(set.contains(Flag::Bar)); /// assert!(set.contains(Flag::Baz)); /// ``` #[inline] pub fn full() -> Self { let mut set = Self::default(); for f in F::LIST { set |= *f } set } /// Returns the raw bits of the set. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u16 { /// Foo = 0b0001, /// Bar = 0b0010, /// Baz = 0b0100, /// } /// } /// /// let set = Flag::Foo | Flag::Baz; /// assert_eq!(set.bits(), 0b0101u16); /// ``` #[inline] pub fn bits(self) -> F::Type { self.0 } /// Returns true if the FlagSet contains no flags. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u8 { /// Foo = 1, /// Bar = 2, /// Baz = 4 /// } /// } /// /// let mut set = Flag::Foo | Flag::Bar; /// assert!(!set.is_empty()); /// /// set &= Flag::Baz; /// assert!(set.is_empty()); /// ``` #[inline] pub fn is_empty(self) -> bool { self == Self::default() } /// Returns true if the FlagSet contains all possible flags. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u8 { /// Foo = 1, /// Bar = 2, /// Baz = 4 /// } /// } /// /// let mut set = Flag::Foo | Flag::Bar; /// assert!(!set.is_full()); /// /// set |= Flag::Baz; /// assert!(set.is_full()); /// ``` #[inline] pub fn is_full(self) -> bool { self == Self::full() } /// Returns true if the two `FlagSet`s do not share any flags. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u8 { /// Foo = 1, /// Bar = 2, /// Baz = 4 /// } /// } /// /// let set = Flag::Foo | Flag::Bar; /// assert!(!set.is_disjoint(Flag::Foo)); /// assert!(!set.is_disjoint(Flag::Foo | Flag::Baz)); /// assert!(set.is_disjoint(Flag::Baz)); /// ``` #[inline] pub fn is_disjoint(self, rhs: impl Into>) -> bool { self & rhs == Self::default() } /// Returns true if this FlagSet is a superset of the specified flags. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u8 { /// Foo = 1, /// Bar = 2, /// Baz = 4 /// } /// } /// /// let set = Flag::Foo | Flag::Bar; /// assert!(set.contains(Flag::Foo)); /// assert!(set.contains(Flag::Foo | Flag::Bar)); /// assert!(!set.contains(Flag::Foo | Flag::Bar | Flag::Baz)); /// ``` #[inline] pub fn contains(self, rhs: impl Into>) -> bool { let rhs = rhs.into(); self & rhs == rhs } /// Removes all flags from the FlagSet. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u8 { /// Foo = 1, /// Bar = 2, /// Baz = 4 /// } /// } /// /// let mut set = Flag::Foo | Flag::Bar; /// assert!(!set.is_empty()); /// /// set.clear(); /// assert!(set.is_empty()); /// ``` #[inline] pub fn clear(&mut self) { *self = Self::default(); } /// Clears the current set and returns an iterator of all removed flags. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u8 { /// Foo = 1, /// Bar = 2, /// Baz = 4 /// } /// } /// /// let mut set = Flag::Foo | Flag::Bar; /// let mut iter = set.drain(); /// assert!(set.is_empty()); /// assert_eq!(iter.next(), Some(Flag::Foo)); /// assert_eq!(iter.next(), Some(Flag::Bar)); /// assert_eq!(iter.next(), None); /// ``` #[inline] pub fn drain(&mut self) -> Iter { let iter = self.into_iter(); *self = Self::default(); iter } /// Retain only the flags flags specified by the predicate. /// /// ``` /// use flagset::{FlagSet, flags}; /// /// flags! { /// pub enum Flag: u8 { /// Foo = 1, /// Bar = 2, /// Baz = 4 /// } /// } /// /// let mut set0 = Flag::Foo | Flag::Bar; /// set0.retain(|f| f != Flag::Foo); /// assert_eq!(set0, Flag::Bar); /// ``` #[inline] pub fn retain(&mut self, func: impl Fn(F) -> bool) { for f in self.into_iter() { if !func(f) { *self -= f } } } } #[cfg(feature = "serde")] impl serde::Serialize for FlagSet where F::Type: serde::ser::Serialize, { #[inline] fn serialize(&self, serializer: S) -> core::result::Result where S: serde::ser::Serializer, { self.0.serialize(serializer) } } #[cfg(feature = "serde")] impl<'de, F: Flags> serde::Deserialize<'de> for FlagSet where F::Type: serde::de::Deserialize<'de>, { #[inline] fn deserialize(deserializer: D) -> core::result::Result where D: serde::de::Deserializer<'de>, { Ok(FlagSet(F::Type::deserialize(deserializer)?)) } } /// Define flag value using the `enum` syntax. See below for details. /// /// Each enumeration value **MUST** have a specified value. /// /// The width of the bitfield **MUST** also be specified by its integer type. /// /// It is important to note that the size of the flag enumeration itself is /// unrelated to the size of the corresponding `FlagSet` instance. /// /// It is also worth noting that this macro automatically implements a variety /// of standard traits including: /// * Copy /// * Clone /// * Debug /// * PartialEq /// * Eq /// * From<$enum> for $integer /// * Not /// * BitAnd /// * BitOr /// * BitXor /// * Sub /// * Rem /// /// ``` /// use std::mem::{align_of, size_of}; /// use flagset::{FlagSet, flags}; /// /// flags! { /// enum FlagEmpty: u32 {} /// /// enum Flag8: u8 { /// Foo = 0b001, /// Bar = 0b010, /// Baz = 0b100 /// } /// /// pub enum Flag16: u16 { /// Foo, /// Bar, /// #[deprecated] /// Baz, /// } /// /// #[derive(PartialOrd, Ord)] /// enum Flag32: u32 { /// Foo = 0b001, /// #[deprecated] /// Bar = 0b010, /// Baz = 0b100 /// } /// /// #[repr(u64)] /// enum Flag64: u64 { /// Foo = 0b001, /// Bar = 0b010, /// Baz = 0b100 /// } /// /// #[repr(u32)] /// enum Flag128: u128 { /// Foo = 0b001, /// Bar = 0b010, /// Baz = 0b100 /// } /// } /// /// assert_eq!(size_of::(), 1); /// assert_eq!(size_of::(), 1); /// assert_eq!(size_of::(), 1); /// assert_eq!(size_of::(), 8); /// assert_eq!(size_of::(), 4); /// /// assert_eq!(align_of::(), 1); /// assert_eq!(align_of::(), 1); /// assert_eq!(align_of::(), 1); /// assert_eq!(align_of::(), align_of::()); /// assert_eq!(align_of::(), align_of::()); /// /// assert_eq!(size_of::>(), size_of::()); /// assert_eq!(size_of::>(), size_of::()); /// assert_eq!(size_of::>(), size_of::()); /// assert_eq!(size_of::>(), size_of::()); /// assert_eq!(size_of::>(), size_of::()); /// /// assert_eq!(align_of::>(), align_of::()); /// assert_eq!(align_of::>(), align_of::()); /// assert_eq!(align_of::>(), align_of::()); /// assert_eq!(align_of::>(), align_of::()); /// assert_eq!(align_of::>(), align_of::()); /// ``` #[macro_export] macro_rules! flags { () => {}; // Entry point for enumerations without values. ($(#[$m:meta])* $p:vis enum $n:ident: $t:ty { $($(#[$a:meta])* $k:ident),+ $(,)* } $($next:tt)*) => { $crate::flags! { $(#[$m])* $p enum $n: $t { $($(#[$a])* $k = (1 << $n::$k as $t)),+ } $($next)* } }; // Entrypoint for enumerations with values. ($(#[$m:meta])* $p:vis enum $n:ident: $t:ty { $($(#[$a:meta])*$k:ident = $v:expr),* $(,)* } $($next:tt)*) => { $(#[$m])* #[derive(Copy, Clone, Debug, PartialEq, Eq)] $p enum $n { $($(#[$a])* $k),* } impl $crate::Flags for $n { type Type = $t; const LIST: &'static [Self] = &[$($n::$k),*]; } impl core::convert::From<$n> for $crate::FlagSet<$n> { #[inline] fn from(value: $n) -> Self { unsafe { match value { $($n::$k => Self::new_unchecked($v)),* } } } } impl core::ops::Not for $n { type Output = $crate::FlagSet<$n>; #[inline] fn not(self) -> Self::Output { !$crate::FlagSet::from(self) } } impl>> core::ops::BitAnd for $n { type Output = $crate::FlagSet<$n>; #[inline] fn bitand(self, rhs: R) -> Self::Output { $crate::FlagSet::from(self) & rhs } } impl>> core::ops::BitOr for $n { type Output = $crate::FlagSet<$n>; #[inline] fn bitor(self, rhs: R) -> Self::Output { $crate::FlagSet::from(self) | rhs } } impl>> core::ops::BitXor for $n { type Output = $crate::FlagSet<$n>; #[inline] fn bitxor(self, rhs: R) -> Self::Output { $crate::FlagSet::from(self) ^ rhs } } impl>> core::ops::Sub for $n { type Output = $crate::FlagSet<$n>; #[inline] fn sub(self, rhs: R) -> Self::Output { $crate::FlagSet::from(self) - rhs } } impl>> core::ops::Rem for $n { type Output = $crate::FlagSet<$n>; #[inline] fn rem(self, rhs: R) -> Self::Output { $crate::FlagSet::from(self) % rhs } } $crate::flags! { $($next)* } }; }