From fa6723a9686c73b6c7a2d6a2d77987acb4ece533 Mon Sep 17 00:00:00 2001 From: Jakob Vukalovic Date: Wed, 26 Apr 2023 10:38:55 +0100 Subject: Upgrade to 2.2.1 Upgrade bitflags crate to version 2.2.1. Tests are removed because they depend on another crate which has currently not been imported to Android. Test: Build Change-Id: I7c925a5336e13d042f82e68abcbe23bb774cd586 Merged-In: I2cdb005d4902f6a95a8e90ac2565acfd604c5af9 --- .cargo_vcs_info.json | 7 +- 1.3.2/.cargo_vcs_info.json | 5 + 1.3.2/.github/workflows/rust.yml | 56 + 1.3.2/.gitignore | 5 + 1.3.2/Android.bp | 109 ++ 1.3.2/CHANGELOG.md | 206 +++ 1.3.2/CODE_OF_CONDUCT.md | 73 + 1.3.2/Cargo.toml | 58 + 1.3.2/Cargo.toml.orig | 39 + 1.3.2/LICENSE | 1 + 1.3.2/LICENSE-APACHE | 201 +++ 1.3.2/LICENSE-MIT | 25 + 1.3.2/METADATA | 19 + 1.3.2/MODULE_LICENSE_APACHE2 | 0 1.3.2/OWNERS | 1 + 1.3.2/README.md | 32 + 1.3.2/TEST_MAPPING | 93 ++ 1.3.2/cargo2android.json | 19 + 1.3.2/patches/std.diff | 14 + 1.3.2/src/example_generated.rs | 14 + 1.3.2/src/lib.rs | 1730 ++++++++++++++++++++ 1.3.2/tests/basic.rs | 20 + 1.3.2/tests/compile-fail/.gitignore | 1 + 1.3.2/tests/compile-fail/impls/copy.rs | 10 + 1.3.2/tests/compile-fail/impls/copy.stderr.beta | 27 + 1.3.2/tests/compile-fail/impls/eq.rs | 10 + 1.3.2/tests/compile-fail/impls/eq.stderr.beta | 55 + .../compile-fail/non_integer_base/all_defined.rs | 123 ++ .../non_integer_base/all_defined.stderr.beta | 27 + .../compile-fail/non_integer_base/all_missing.rs | 13 + .../non_integer_base/all_missing.stderr.beta | 13 + .../tests/compile-fail/visibility/private_field.rs | 13 + .../visibility/private_field.stderr.beta | 10 + .../tests/compile-fail/visibility/private_flags.rs | 18 + .../visibility/private_flags.stderr.beta | 18 + 1.3.2/tests/compile-fail/visibility/pub_const.rs | 9 + .../compile-fail/visibility/pub_const.stderr.beta | 5 + 1.3.2/tests/compile-pass/impls/convert.rs | 17 + 1.3.2/tests/compile-pass/impls/default.rs | 10 + 1.3.2/tests/compile-pass/impls/inherent_methods.rs | 15 + 1.3.2/tests/compile-pass/redefinition/core.rs | 14 + 1.3.2/tests/compile-pass/redefinition/stringify.rs | 19 + 1.3.2/tests/compile-pass/repr/c.rs | 10 + 1.3.2/tests/compile-pass/repr/transparent.rs | 10 + 1.3.2/tests/compile-pass/visibility/bits_field.rs | 11 + 1.3.2/tests/compile-pass/visibility/pub_in.rs | 19 + 1.3.2/tests/compile.rs | 63 + Android.bp | 60 +- CHANGELOG.md | 166 +- CONTRIBUTING.md | 9 + Cargo.toml | 70 +- Cargo.toml.orig | 23 +- METADATA | 14 +- README.md | 34 +- SECURITY.md | 13 + TEST_MAPPING | 18 +- benches/parse.rs | 96 ++ cargo2android.json | 13 +- examples/fmt.rs | 49 + examples/serde.rs | 36 + patches/std.diff | 16 +- src/example_generated.rs | 48 +- src/external.rs | 260 +++ src/external/arbitrary_support.rs | 19 + src/external/bytemuck_support.rs | 19 + src/external/serde_support.rs | 84 + src/internal.rs | 570 +++++++ src/lib.rs | 1435 ++++++++-------- src/parser.rs | 123 ++ src/public.rs | 467 ++++++ src/traits.rs | 157 ++ 71 files changed, 6191 insertions(+), 875 deletions(-) create mode 100644 1.3.2/.cargo_vcs_info.json create mode 100644 1.3.2/.github/workflows/rust.yml create mode 100644 1.3.2/.gitignore create mode 100644 1.3.2/Android.bp create mode 100644 1.3.2/CHANGELOG.md create mode 100644 1.3.2/CODE_OF_CONDUCT.md create mode 100644 1.3.2/Cargo.toml create mode 100644 1.3.2/Cargo.toml.orig create mode 120000 1.3.2/LICENSE create mode 100644 1.3.2/LICENSE-APACHE create mode 100644 1.3.2/LICENSE-MIT create mode 100644 1.3.2/METADATA create mode 100644 1.3.2/MODULE_LICENSE_APACHE2 create mode 100644 1.3.2/OWNERS create mode 100644 1.3.2/README.md create mode 100644 1.3.2/TEST_MAPPING create mode 100644 1.3.2/cargo2android.json create mode 100644 1.3.2/patches/std.diff create mode 100644 1.3.2/src/example_generated.rs create mode 100644 1.3.2/src/lib.rs create mode 100644 1.3.2/tests/basic.rs create mode 100644 1.3.2/tests/compile-fail/.gitignore create mode 100644 1.3.2/tests/compile-fail/impls/copy.rs create mode 100644 1.3.2/tests/compile-fail/impls/copy.stderr.beta create mode 100644 1.3.2/tests/compile-fail/impls/eq.rs create mode 100644 1.3.2/tests/compile-fail/impls/eq.stderr.beta create mode 100644 1.3.2/tests/compile-fail/non_integer_base/all_defined.rs create mode 100644 1.3.2/tests/compile-fail/non_integer_base/all_defined.stderr.beta create mode 100644 1.3.2/tests/compile-fail/non_integer_base/all_missing.rs create mode 100644 1.3.2/tests/compile-fail/non_integer_base/all_missing.stderr.beta create mode 100644 1.3.2/tests/compile-fail/visibility/private_field.rs create mode 100644 1.3.2/tests/compile-fail/visibility/private_field.stderr.beta create mode 100644 1.3.2/tests/compile-fail/visibility/private_flags.rs create mode 100644 1.3.2/tests/compile-fail/visibility/private_flags.stderr.beta create mode 100644 1.3.2/tests/compile-fail/visibility/pub_const.rs create mode 100644 1.3.2/tests/compile-fail/visibility/pub_const.stderr.beta create mode 100644 1.3.2/tests/compile-pass/impls/convert.rs create mode 100644 1.3.2/tests/compile-pass/impls/default.rs create mode 100644 1.3.2/tests/compile-pass/impls/inherent_methods.rs create mode 100644 1.3.2/tests/compile-pass/redefinition/core.rs create mode 100644 1.3.2/tests/compile-pass/redefinition/stringify.rs create mode 100644 1.3.2/tests/compile-pass/repr/c.rs create mode 100644 1.3.2/tests/compile-pass/repr/transparent.rs create mode 100644 1.3.2/tests/compile-pass/visibility/bits_field.rs create mode 100644 1.3.2/tests/compile-pass/visibility/pub_in.rs create mode 100644 1.3.2/tests/compile.rs create mode 100644 CONTRIBUTING.md create mode 100644 SECURITY.md create mode 100644 benches/parse.rs create mode 100644 examples/fmt.rs create mode 100644 examples/serde.rs create mode 100644 src/external.rs create mode 100644 src/external/arbitrary_support.rs create mode 100644 src/external/bytemuck_support.rs create mode 100644 src/external/serde_support.rs create mode 100644 src/internal.rs create mode 100644 src/parser.rs create mode 100644 src/public.rs create mode 100644 src/traits.rs diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json index 8e82c01..b28c102 100644 --- a/.cargo_vcs_info.json +++ b/.cargo_vcs_info.json @@ -1,5 +1,6 @@ { "git": { - "sha1": "ed185cfb1c447c1b4bd6ac021c9ec3bb02c9e2f2" - } -} + "sha1": "0c318c0d77ed63ad4ee9bfdf1d2c486993b18b37" + }, + "path_in_vcs": "" +} \ No newline at end of file diff --git a/1.3.2/.cargo_vcs_info.json b/1.3.2/.cargo_vcs_info.json new file mode 100644 index 0000000..8e82c01 --- /dev/null +++ b/1.3.2/.cargo_vcs_info.json @@ -0,0 +1,5 @@ +{ + "git": { + "sha1": "ed185cfb1c447c1b4bd6ac021c9ec3bb02c9e2f2" + } +} diff --git a/1.3.2/.github/workflows/rust.yml b/1.3.2/.github/workflows/rust.yml new file mode 100644 index 0000000..ffe0eda --- /dev/null +++ b/1.3.2/.github/workflows/rust.yml @@ -0,0 +1,56 @@ +name: Rust + +on: [push, pull_request] + +env: + CARGO_TERM_COLOR: always + +jobs: + check: + name: Test + runs-on: ubuntu-latest + strategy: + fail-fast: true + matrix: + rust: + - stable + - beta + - nightly + - 1.46.0 + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: ${{ matrix.rust }} + override: true + + - name: Default features + uses: actions-rs/cargo@v1 + with: + command: test + args: --features example_generated + + embedded: + name: Build (embedded) + runs-on: ubuntu-latest + steps: + - name: Checkout sources + uses: actions/checkout@v2 + + - name: Install Rust toolchain + uses: actions-rs/toolchain@v1 + with: + profile: minimal + toolchain: nightly + target: thumbv6m-none-eabi + override: true + + - name: Default features + uses: actions-rs/cargo@v1 + with: + command: build + args: -Z avoid-dev-deps --features example_generated --target thumbv6m-none-eabi diff --git a/1.3.2/.gitignore b/1.3.2/.gitignore new file mode 100644 index 0000000..61c3331 --- /dev/null +++ b/1.3.2/.gitignore @@ -0,0 +1,5 @@ +wip +target +Cargo.lock + +/.idea/ diff --git a/1.3.2/Android.bp b/1.3.2/Android.bp new file mode 100644 index 0000000..2466b99 --- /dev/null +++ b/1.3.2/Android.bp @@ -0,0 +1,109 @@ +// This file is generated by cargo2android.py --config cargo2android.json. +// Do not modify this file as changes will be overridden on upgrade. + +package { + default_applicable_licenses: ["external_rust_crates_bitflags_license"], +} + +// Added automatically by a large-scale-change that took the approach of +// 'apply every license found to every target'. While this makes sure we respect +// every license restriction, it may not be entirely correct. +// +// e.g. GPL in an MIT project might only apply to the contrib/ directory. +// +// Please consider splitting the single license below into multiple licenses, +// taking care not to lose any license_kind information, and overriding the +// default license using the 'licenses: [...]' property on targets as needed. +// +// For unused files, consider creating a 'fileGroup' with "//visibility:private" +// to attach the license to, and including a comment whether the files may be +// used in the current project. +// +// large-scale-change included anything that looked like it might be a license +// text as a license_text. e.g. LICENSE, NOTICE, COPYING etc. +// +// Please consider removing redundant or irrelevant files from 'license_text:'. +// See: http://go/android-license-faq +license { + name: "external_rust_crates_bitflags_license-1.3.2", + visibility: [":__subpackages__"], + license_kinds: [ + "SPDX-license-identifier-Apache-2.0", + "SPDX-license-identifier-MIT", + ], + license_text: [ + "LICENSE-APACHE", + "LICENSE-MIT", + ], +} + +rust_test { + name: "bitflags_test_src_lib-1.3.2", + host_supported: true, + crate_name: "bitflags", + cargo_env_compat: true, + cargo_pkg_version: "1.3.2", + srcs: ["src/lib.rs"], + test_suites: ["general-tests"], + auto_gen_config: true, + test_options: { + unit_test: true, + }, + edition: "2018", + features: ["default"], + rustlibs: [ + "libserde", + "libserde_json", + "libwalkdir", + ], + proc_macros: [ + "librustversion", + "libserde_derive", + ], +} + +rust_test { + name: "bitflags_test_tests_basic-1.3.2", + host_supported: true, + crate_name: "bitflags", + cargo_env_compat: true, + cargo_pkg_version: "1.3.2", + srcs: ["tests/basic.rs"], + test_suites: ["general-tests"], + auto_gen_config: true, + test_options: { + unit_test: true, + }, + edition: "2018", + features: ["default"], + rustlibs: [ + "libbitflags-1.3.2", + "libserde", + "libserde_json", + "libwalkdir", + ], + proc_macros: [ + "librustversion", + "libserde_derive", + ], +} + +rust_library { + name: "libbitflags-1.3.2", + host_supported: true, + crate_name: "bitflags", + cargo_env_compat: true, + cargo_pkg_version: "1.3.2", + srcs: ["src/lib.rs"], + edition: "2018", + features: ["default"], + apex_available: [ + "//apex_available:platform", + "com.android.btservices", + "com.android.compos", + "com.android.virt", + ], + product_available: true, + vendor_available: true, + min_sdk_version: "29", +} diff --git a/1.3.2/CHANGELOG.md b/1.3.2/CHANGELOG.md new file mode 100644 index 0000000..12fea16 --- /dev/null +++ b/1.3.2/CHANGELOG.md @@ -0,0 +1,206 @@ +# 1.3.2 + +- Allow `non_snake_case` in generated flags types ([#256]) + +[#252]: https://github.com/bitflags/bitflags/pull/256 + +# 1.3.1 + +- Revert unconditional `#[repr(transparent)]` ([#252]) + +[#252]: https://github.com/bitflags/bitflags/pull/252 + +# 1.3.0 (yanked) + +- Add `#[repr(transparent)]` ([#187]) + +- End `empty` doc comment with full stop ([#202]) + +- Fix typo in crate root docs ([#206]) + +- Document from_bits_unchecked unsafety ([#207]) + +- Let `is_all` ignore extra bits ([#211]) + +- Allows empty flag definition ([#225]) + +- Making crate accessible from std ([#227]) + +- Make `from_bits` a const fn ([#229]) + +- Allow multiple bitflags structs in one macro invocation ([#235]) + +- Add named functions to perform set operations ([#244]) + +- Fix typos in method docs ([#245]) + +- Modernization of the `bitflags` macro to take advantage of newer features and 2018 idioms ([#246]) + +- Fix regression (in an unreleased feature) and simplify tests ([#247]) + +- Use `Self` and fix bug when overriding `stringify!` ([#249]) + +[#187]: https://github.com/bitflags/bitflags/pull/187 +[#202]: https://github.com/bitflags/bitflags/pull/202 +[#206]: https://github.com/bitflags/bitflags/pull/206 +[#207]: https://github.com/bitflags/bitflags/pull/207 +[#211]: https://github.com/bitflags/bitflags/pull/211 +[#225]: https://github.com/bitflags/bitflags/pull/225 +[#227]: https://github.com/bitflags/bitflags/pull/227 +[#229]: https://github.com/bitflags/bitflags/pull/229 +[#235]: https://github.com/bitflags/bitflags/pull/235 +[#244]: https://github.com/bitflags/bitflags/pull/244 +[#245]: https://github.com/bitflags/bitflags/pull/245 +[#246]: https://github.com/bitflags/bitflags/pull/246 +[#247]: https://github.com/bitflags/bitflags/pull/247 +[#249]: https://github.com/bitflags/bitflags/pull/249 + +# 1.2.1 + +- Remove extraneous `#[inline]` attributes ([#194]) + +[#194]: https://github.com/bitflags/bitflags/pull/194 + +# 1.2.0 + +- Fix typo: {Lower, Upper}Exp - {Lower, Upper}Hex ([#183]) + +- Add support for "unknown" bits ([#188]) + +[#183]: https://github.com/rust-lang-nursery/bitflags/pull/183 +[#188]: https://github.com/rust-lang-nursery/bitflags/pull/188 + +# 1.1.0 + +This is a re-release of `1.0.5`, which was yanked due to a bug in the RLS. + +# 1.0.5 + +- Use compiletest_rs flags supported by stable toolchain ([#171]) + +- Put the user provided attributes first ([#173]) + +- Make bitflags methods `const` on newer compilers ([#175]) + +[#171]: https://github.com/rust-lang-nursery/bitflags/pull/171 +[#173]: https://github.com/rust-lang-nursery/bitflags/pull/173 +[#175]: https://github.com/rust-lang-nursery/bitflags/pull/175 + +# 1.0.4 + +- Support Rust 2018 style macro imports ([#165]) + + ```rust + use bitflags::bitflags; + ``` + +[#165]: https://github.com/rust-lang-nursery/bitflags/pull/165 + +# 1.0.3 + +- Improve zero value flag handling and documentation ([#157]) + +[#157]: https://github.com/rust-lang-nursery/bitflags/pull/157 + +# 1.0.2 + +- 30% improvement in compile time of bitflags crate ([#156]) + +- Documentation improvements ([#153]) + +- Implementation cleanup ([#149]) + +[#156]: https://github.com/rust-lang-nursery/bitflags/pull/156 +[#153]: https://github.com/rust-lang-nursery/bitflags/pull/153 +[#149]: https://github.com/rust-lang-nursery/bitflags/pull/149 + +# 1.0.1 +- Add support for `pub(restricted)` specifier on the bitflags struct ([#135]) +- Optimize performance of `all()` when called from a separate crate ([#136]) + +[#135]: https://github.com/rust-lang-nursery/bitflags/pull/135 +[#136]: https://github.com/rust-lang-nursery/bitflags/pull/136 + +# 1.0.0 +- **[breaking change]** Macro now generates [associated constants](https://doc.rust-lang.org/reference/items.html#associated-constants) ([#24]) + +- **[breaking change]** Minimum supported version is Rust **1.20**, due to usage of associated constants + +- After being broken in 0.9, the `#[deprecated]` attribute is now supported again ([#112]) + +- Other improvements to unit tests and documentation ([#106] and [#115]) + +[#24]: https://github.com/rust-lang-nursery/bitflags/pull/24 +[#106]: https://github.com/rust-lang-nursery/bitflags/pull/106 +[#112]: https://github.com/rust-lang-nursery/bitflags/pull/112 +[#115]: https://github.com/rust-lang-nursery/bitflags/pull/115 + +## How to update your code to use associated constants +Assuming the following structure definition: +```rust +bitflags! { + struct Something: u8 { + const FOO = 0b01, + const BAR = 0b10 + } +} +``` +In 0.9 and older you could do: +```rust +let x = FOO.bits | BAR.bits; +``` +Now you must use: +```rust +let x = Something::FOO.bits | Something::BAR.bits; +``` + +# 0.9.1 +- Fix the implementation of `Formatting` traits when other formatting traits were present in scope ([#105]) + +[#105]: https://github.com/rust-lang-nursery/bitflags/pull/105 + +# 0.9.0 +- **[breaking change]** Use struct keyword instead of flags to define bitflag types ([#84]) + +- **[breaking change]** Terminate const items with semicolons instead of commas ([#87]) + +- Implement the `Hex`, `Octal`, and `Binary` formatting traits ([#86]) + +- Printing an empty flag value with the `Debug` trait now prints "(empty)" instead of nothing ([#85]) + +- The `bitflags!` macro can now be used inside of a fn body, to define a type local to that function ([#74]) + +[#74]: https://github.com/rust-lang-nursery/bitflags/pull/74 +[#84]: https://github.com/rust-lang-nursery/bitflags/pull/84 +[#85]: https://github.com/rust-lang-nursery/bitflags/pull/85 +[#86]: https://github.com/rust-lang-nursery/bitflags/pull/86 +[#87]: https://github.com/rust-lang-nursery/bitflags/pull/87 + +# 0.8.2 +- Update feature flag used when building bitflags as a dependency of the Rust toolchain + +# 0.8.1 +- Allow bitflags to be used as a dependency of the Rust toolchain + +# 0.8.0 +- Add support for the experimental `i128` and `u128` integer types ([#57]) +- Add set method: `flags.set(SOME_FLAG, true)` or `flags.set(SOME_FLAG, false)` ([#55]) + This may break code that defines its own set method + +[#55]: https://github.com/rust-lang-nursery/bitflags/pull/55 +[#57]: https://github.com/rust-lang-nursery/bitflags/pull/57 + +# 0.7.1 +*(yanked)* + +# 0.7.0 +- Implement the Extend trait ([#49]) +- Allow definitions inside the `bitflags!` macro to refer to items imported from other modules ([#51]) + +[#49]: https://github.com/rust-lang-nursery/bitflags/pull/49 +[#51]: https://github.com/rust-lang-nursery/bitflags/pull/51 + +# 0.6.0 +- The `no_std` feature was removed as it is now the default +- The `assignment_operators` feature was remove as it is now enabled by default +- Some clippy suggestions have been applied diff --git a/1.3.2/CODE_OF_CONDUCT.md b/1.3.2/CODE_OF_CONDUCT.md new file mode 100644 index 0000000..f7add90 --- /dev/null +++ b/1.3.2/CODE_OF_CONDUCT.md @@ -0,0 +1,73 @@ +# Contributor Covenant Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to making participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +education, socio-economic status, nationality, personal appearance, race, +religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or + advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at coc@senaite.org. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html + +[homepage]: https://www.contributor-covenant.org \ No newline at end of file diff --git a/1.3.2/Cargo.toml b/1.3.2/Cargo.toml new file mode 100644 index 0000000..9d54c72 --- /dev/null +++ b/1.3.2/Cargo.toml @@ -0,0 +1,58 @@ +# 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 believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "bitflags" +version = "1.3.2" +authors = ["The Rust Project Developers"] +exclude = ["bors.toml"] +description = "A macro to generate structures which behave like bitflags.\n" +homepage = "https://github.com/bitflags/bitflags" +documentation = "https://docs.rs/bitflags" +readme = "README.md" +keywords = ["bit", "bitmask", "bitflags", "flags"] +categories = ["no-std"] +license = "MIT/Apache-2.0" +repository = "https://github.com/bitflags/bitflags" +[package.metadata.docs.rs] +features = ["example_generated"] +[dependencies.compiler_builtins] +version = "0.1.2" +optional = true + +[dependencies.core] +version = "1.0.0" +optional = true +package = "rustc-std-workspace-core" +[dev-dependencies.rustversion] +version = "1.0" + +[dev-dependencies.serde] +version = "1.0" + +[dev-dependencies.serde_derive] +version = "1.0" + +[dev-dependencies.serde_json] +version = "1.0" + +[dev-dependencies.trybuild] +version = "1.0" + +[dev-dependencies.walkdir] +version = "2.3" + +[features] +default = [] +example_generated = [] +rustc-dep-of-std = ["core", "compiler_builtins"] diff --git a/1.3.2/Cargo.toml.orig b/1.3.2/Cargo.toml.orig new file mode 100644 index 0000000..be9e05a --- /dev/null +++ b/1.3.2/Cargo.toml.orig @@ -0,0 +1,39 @@ +[package] +name = "bitflags" +# NB: When modifying, also modify: +# 1. html_root_url in lib.rs +# 2. number in readme (for breaking changes) +version = "1.3.2" +edition = "2018" +authors = ["The Rust Project Developers"] +license = "MIT/Apache-2.0" +keywords = ["bit", "bitmask", "bitflags", "flags"] +readme = "README.md" +repository = "https://github.com/bitflags/bitflags" +homepage = "https://github.com/bitflags/bitflags" +documentation = "https://docs.rs/bitflags" +categories = ["no-std"] +description = """ +A macro to generate structures which behave like bitflags. +""" +exclude = ["bors.toml"] + +[dependencies] +core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' } +compiler_builtins = { version = '0.1.2', optional = true } + +[dev-dependencies] +trybuild = "1.0" +rustversion = "1.0" +walkdir = "2.3" +serde = "1.0" +serde_derive = "1.0" +serde_json = "1.0" + +[features] +default = [] +example_generated = [] +rustc-dep-of-std = ["core", "compiler_builtins"] + +[package.metadata.docs.rs] +features = ["example_generated"] diff --git a/1.3.2/LICENSE b/1.3.2/LICENSE new file mode 120000 index 0000000..6b579aa --- /dev/null +++ b/1.3.2/LICENSE @@ -0,0 +1 @@ +LICENSE-APACHE \ No newline at end of file diff --git a/1.3.2/LICENSE-APACHE b/1.3.2/LICENSE-APACHE new file mode 100644 index 0000000..16fe87b --- /dev/null +++ b/1.3.2/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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. diff --git a/1.3.2/LICENSE-MIT b/1.3.2/LICENSE-MIT new file mode 100644 index 0000000..39d4bdb --- /dev/null +++ b/1.3.2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +Permission is hereby granted, free of charge, to any +person obtaining a copy of this software and associated +documentation files (the "Software"), to deal in the +Software without restriction, including without +limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of +the Software, and to permit persons to whom the Software +is furnished to do so, subject to the following +conditions: + +The above copyright notice and this permission notice +shall be included in all copies or substantial portions +of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF +ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED +TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A +PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT +SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY +CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR +IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/1.3.2/METADATA b/1.3.2/METADATA new file mode 100644 index 0000000..0e660ff --- /dev/null +++ b/1.3.2/METADATA @@ -0,0 +1,19 @@ +name: "bitflags" +description: "A macro to generate structures which behave like bitflags." +third_party { + url { + type: HOMEPAGE + value: "https://crates.io/crates/bitflags" + } + url { + type: ARCHIVE + value: "https://static.crates.io/crates/bitflags/bitflags-1.3.2.crate" + } + version: "1.3.2" + license_type: NOTICE + last_upgrade_date { + year: 2021 + month: 9 + day: 22 + } +} diff --git a/1.3.2/MODULE_LICENSE_APACHE2 b/1.3.2/MODULE_LICENSE_APACHE2 new file mode 100644 index 0000000..e69de29 diff --git a/1.3.2/OWNERS b/1.3.2/OWNERS new file mode 100644 index 0000000..46fc303 --- /dev/null +++ b/1.3.2/OWNERS @@ -0,0 +1 @@ +include platform/prebuilts/rust:/OWNERS diff --git a/1.3.2/README.md b/1.3.2/README.md new file mode 100644 index 0000000..0da0f85 --- /dev/null +++ b/1.3.2/README.md @@ -0,0 +1,32 @@ +bitflags +======== + +[![Rust](https://github.com/bitflags/bitflags/workflows/Rust/badge.svg)](https://github.com/bitflags/bitflags/actions) +[![Join the chat at https://gitter.im/bitflags/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bitflags/Lobby?utm_source=badge&utm_medium=badge&utm_content=badge) +[![Latest version](https://img.shields.io/crates/v/bitflags.svg)](https://crates.io/crates/bitflags) +[![Documentation](https://docs.rs/bitflags/badge.svg)](https://docs.rs/bitflags) +![License](https://img.shields.io/crates/l/bitflags.svg) + +A Rust macro to generate structures which behave like a set of bitflags + +- [Documentation](https://docs.rs/bitflags) +- [Release notes](https://github.com/bitflags/bitflags/releases) + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +bitflags = "1.3" +``` + +and this to your source code: + +```rust +use bitflags::bitflags; +``` + +## Rust Version Support + +The minimum supported Rust version is 1.46 due to use of associated constants and const functions. diff --git a/1.3.2/TEST_MAPPING b/1.3.2/TEST_MAPPING new file mode 100644 index 0000000..342b698 --- /dev/null +++ b/1.3.2/TEST_MAPPING @@ -0,0 +1,93 @@ +// Generated by update_crate_tests.py for tests that depend on this crate. +{ + "imports": [ + { + "path": "external/rust/crates/base64" + }, + { + "path": "external/rust/crates/clap/2.33.3" + }, + { + "path": "external/rust/crates/gdbstub_arch" + }, + { + "path": "external/rust/crates/libsqlite3-sys" + }, + { + "path": "external/rust/crates/tinytemplate" + }, + { + "path": "external/rust/crates/tinyvec" + }, + { + "path": "external/rust/crates/tokio" + }, + { + "path": "external/rust/crates/unicode-xid" + }, + { + "path": "external/rust/crates/virtio-drivers" + }, + { + "path": "packages/modules/Virtualization/apkdmverity" + }, + { + "path": "packages/modules/Virtualization/authfs" + }, + { + "path": "packages/modules/Virtualization/avmd" + }, + { + "path": "packages/modules/Virtualization/encryptedstore" + }, + { + "path": "packages/modules/Virtualization/libs/apkverify" + }, + { + "path": "packages/modules/Virtualization/libs/capabilities" + }, + { + "path": "packages/modules/Virtualization/libs/devicemapper" + }, + { + "path": "packages/modules/Virtualization/microdroid_manager" + }, + { + "path": "packages/modules/Virtualization/virtualizationmanager" + }, + { + "path": "packages/modules/Virtualization/vm" + }, + { + "path": "packages/modules/Virtualization/zipfuse" + }, + { + "path": "system/security/diced" + }, + { + "path": "system/security/keystore2" + }, + { + "path": "system/security/keystore2/legacykeystore" + }, + { + "path": "system/security/keystore2/src/crypto" + } + ], + "presubmit": [ + { + "name": "bitflags_test_src_lib-1.3.2" + }, + { + "name": "bitflags_test_tests_basic-1.3.2" + } + ], + "presubmit-rust": [ + { + "name": "bitflags_test_src_lib-1.3.2" + }, + { + "name": "bitflags_test_tests_basic-1.3.2" + } + ] +} diff --git a/1.3.2/cargo2android.json b/1.3.2/cargo2android.json new file mode 100644 index 0000000..73294f5 --- /dev/null +++ b/1.3.2/cargo2android.json @@ -0,0 +1,19 @@ +{ + "apex-available": [ + "//apex_available:platform", + "com.android.btservices", + "com.android.compos", + "com.android.virt" + ], + "dependency-blocklist": [ + "trybuild" + ], + "device": true, + "min-sdk-version": "29", + "run": true, + "test-blocklist": [ + "tests/compile.rs" + ], + "tests": true, + "vendor-available": true +} diff --git a/1.3.2/patches/std.diff b/1.3.2/patches/std.diff new file mode 100644 index 0000000..a34fe97 --- /dev/null +++ b/1.3.2/patches/std.diff @@ -0,0 +1,14 @@ +diff --git a/src/lib.rs b/src/lib.rs +index 935e432..7e87795 100644 +--- a/src/lib.rs ++++ b/src/lib.rs +@@ -275,7 +275,8 @@ + //! + //! Users should generally avoid defining a flag with a value of zero. + +-#![cfg_attr(not(test), no_std)] ++// ANDROID: Use std to allow building as a dylib. ++#![cfg_attr(not(any(test, android_dylib)), no_std)] + #![doc(html_root_url = "https://docs.rs/bitflags/1.3.2")] + + #[doc(hidden)] diff --git a/1.3.2/src/example_generated.rs b/1.3.2/src/example_generated.rs new file mode 100644 index 0000000..cf188d9 --- /dev/null +++ b/1.3.2/src/example_generated.rs @@ -0,0 +1,14 @@ +//! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS +//! CRATE**. + +bitflags! { + /// This is the same `Flags` struct defined in the [crate level example](../index.html#example). + /// Note that this struct is just for documentation purposes only, it must not be used outside + /// this crate. + pub struct Flags: u32 { + const A = 0b00000001; + const B = 0b00000010; + const C = 0b00000100; + const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + } +} diff --git a/1.3.2/src/lib.rs b/1.3.2/src/lib.rs new file mode 100644 index 0000000..7e87795 --- /dev/null +++ b/1.3.2/src/lib.rs @@ -0,0 +1,1730 @@ +// Copyright 2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +//! A typesafe bitmask flag generator useful for sets of C-style bitmask flags. +//! It can be used for creating typesafe wrappers around C APIs. +//! +//! The `bitflags!` macro generates `struct`s that manage a set of flags. The +//! flags should only be defined for integer types, otherwise unexpected type +//! errors may occur at compile time. +//! +//! # Example +//! +//! ``` +//! use bitflags::bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +//! } +//! } +//! +//! fn main() { +//! let e1 = Flags::A | Flags::C; +//! let e2 = Flags::B | Flags::C; +//! assert_eq!((e1 | e2), Flags::ABC); // union +//! assert_eq!((e1 & e2), Flags::C); // intersection +//! assert_eq!((e1 - e2), Flags::A); // set difference +//! assert_eq!(!e2, Flags::A); // set complement +//! } +//! ``` +//! +//! See [`example_generated::Flags`](./example_generated/struct.Flags.html) for documentation of code +//! generated by the above `bitflags!` expansion. +//! +//! The generated `struct`s can also be extended with type and trait +//! implementations: +//! +//! ``` +//! use std::fmt; +//! +//! use bitflags::bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! } +//! } +//! +//! impl Flags { +//! pub fn clear(&mut self) { +//! self.bits = 0; // The `bits` field can be accessed from within the +//! // same module where the `bitflags!` macro was invoked. +//! } +//! } +//! +//! impl fmt::Display for Flags { +//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +//! write!(f, "hi!") +//! } +//! } +//! +//! fn main() { +//! let mut flags = Flags::A | Flags::B; +//! flags.clear(); +//! assert!(flags.is_empty()); +//! assert_eq!(format!("{}", flags), "hi!"); +//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +//! assert_eq!(format!("{:?}", Flags::B), "B"); +//! } +//! ``` +//! +//! # Visibility +//! +//! The generated structs and their associated flag constants are not exported +//! out of the current module by default. A definition can be exported out of +//! the current module by adding `pub` before `struct`: +//! +//! ``` +//! mod example { +//! use bitflags::bitflags; +//! +//! bitflags! { +//! pub struct Flags1: u32 { +//! const A = 0b00000001; +//! } +//! +//! # pub +//! struct Flags2: u32 { +//! const B = 0b00000010; +//! } +//! } +//! } +//! +//! fn main() { +//! let flag1 = example::Flags1::A; +//! let flag2 = example::Flags2::B; // error: const `B` is private +//! } +//! ``` +//! +//! # Attributes +//! +//! Attributes can be attached to the generated `struct`s by placing them +//! before the `struct` keyword. +//! +//! ## Representations +//! +//! It's valid to add a `#[repr(C)]` or `#[repr(transparent)]` attribute to a type +//! generated by `bitflags!`. In these cases, the type is guaranteed to be a newtype. +//! +//! ``` +//! use bitflags::bitflags; +//! +//! bitflags! { +//! #[repr(transparent)] +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! ``` +//! +//! # Trait implementations +//! +//! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash` +//! traits are automatically derived for the `struct`s using the `derive` attribute. +//! Additional traits can be derived by providing an explicit `derive` +//! attribute on `struct`. +//! +//! The `Extend` and `FromIterator` traits are implemented for the `struct`s, +//! too: `Extend` adds the union of the instances of the `struct` iterated over, +//! while `FromIterator` calculates the union. +//! +//! The `Binary`, `Debug`, `LowerHex`, `Octal` and `UpperHex` traits are also +//! implemented by displaying the bits value of the internal struct. +//! +//! ## Operators +//! +//! The following operator traits are implemented for the generated `struct`s: +//! +//! - `BitOr` and `BitOrAssign`: union +//! - `BitAnd` and `BitAndAssign`: intersection +//! - `BitXor` and `BitXorAssign`: toggle +//! - `Sub` and `SubAssign`: set difference +//! - `Not`: set complement +//! +//! # Methods +//! +//! The following methods are defined for the generated `struct`s: +//! +//! - `empty`: an empty set of flags +//! - `all`: the set of all defined flags +//! - `bits`: the raw value of the flags currently stored +//! - `from_bits`: convert from underlying bit representation, unless that +//! representation contains bits that do not correspond to a +//! defined flag +//! - `from_bits_truncate`: convert from underlying bit representation, dropping +//! any bits that do not correspond to defined flags +//! - `from_bits_unchecked`: convert from underlying bit representation, keeping +//! all bits (even those not corresponding to defined +//! flags) +//! - `is_empty`: `true` if no flags are currently stored +//! - `is_all`: `true` if currently set flags exactly equal all defined flags +//! - `intersects`: `true` if there are flags common to both `self` and `other` +//! - `contains`: `true` if all of the flags in `other` are contained within `self` +//! - `insert`: inserts the specified flags in-place +//! - `remove`: removes the specified flags in-place +//! - `toggle`: the specified flags will be inserted if not present, and removed +//! if they are. +//! - `set`: inserts or removes the specified flags depending on the passed value +//! - `intersection`: returns a new set of flags, containing only the flags present +//! in both `self` and `other` (the argument to the function). +//! - `union`: returns a new set of flags, containing any flags present in +//! either `self` or `other` (the argument to the function). +//! - `difference`: returns a new set of flags, containing all flags present in +//! `self` without any of the flags present in `other` (the +//! argument to the function). +//! - `symmetric_difference`: returns a new set of flags, containing all flags +//! present in either `self` or `other` (the argument +//! to the function), but not both. +//! - `complement`: returns a new set of flags, containing all flags which are +//! not set in `self`, but which are allowed for this type. +//! +//! ## Default +//! +//! The `Default` trait is not automatically implemented for the generated structs. +//! +//! If your default value is equal to `0` (which is the same value as calling `empty()` +//! on the generated struct), you can simply derive `Default`: +//! +//! ``` +//! use bitflags::bitflags; +//! +//! bitflags! { +//! // Results in default value with bits: 0 +//! #[derive(Default)] +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! +//! fn main() { +//! let derived_default: Flags = Default::default(); +//! assert_eq!(derived_default.bits(), 0); +//! } +//! ``` +//! +//! If your default value is not equal to `0` you need to implement `Default` yourself: +//! +//! ``` +//! use bitflags::bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! +//! // explicit `Default` implementation +//! impl Default for Flags { +//! fn default() -> Flags { +//! Flags::A | Flags::C +//! } +//! } +//! +//! fn main() { +//! let implemented_default: Flags = Default::default(); +//! assert_eq!(implemented_default, (Flags::A | Flags::C)); +//! } +//! ``` +//! +//! # Zero Flags +//! +//! Flags with a value equal to zero will have some strange behavior that one should be aware of. +//! +//! ``` +//! use bitflags::bitflags; +//! +//! bitflags! { +//! struct Flags: u32 { +//! const NONE = 0b00000000; +//! const SOME = 0b00000001; +//! } +//! } +//! +//! fn main() { +//! let empty = Flags::empty(); +//! let none = Flags::NONE; +//! let some = Flags::SOME; +//! +//! // Zero flags are treated as always present +//! assert!(empty.contains(Flags::NONE)); +//! assert!(none.contains(Flags::NONE)); +//! assert!(some.contains(Flags::NONE)); +//! +//! // Zero flags will be ignored when testing for emptiness +//! assert!(none.is_empty()); +//! } +//! ``` +//! +//! Users should generally avoid defining a flag with a value of zero. + +// ANDROID: Use std to allow building as a dylib. +#![cfg_attr(not(any(test, android_dylib)), no_std)] +#![doc(html_root_url = "https://docs.rs/bitflags/1.3.2")] + +#[doc(hidden)] +pub extern crate core as _core; + +/// The macro used to generate the flag structures. +/// +/// See the [crate level docs](../bitflags/index.html) for complete documentation. +/// +/// # Example +/// +/// ``` +/// use bitflags::bitflags; +/// +/// bitflags! { +/// struct Flags: u32 { +/// const A = 0b00000001; +/// const B = 0b00000010; +/// const C = 0b00000100; +/// const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +/// } +/// } +/// +/// fn main() { +/// let e1 = Flags::A | Flags::C; +/// let e2 = Flags::B | Flags::C; +/// assert_eq!((e1 | e2), Flags::ABC); // union +/// assert_eq!((e1 & e2), Flags::C); // intersection +/// assert_eq!((e1 - e2), Flags::A); // set difference +/// assert_eq!(!e2, Flags::A); // set complement +/// } +/// ``` +/// +/// The generated `struct`s can also be extended with type and trait +/// implementations: +/// +/// ``` +/// use std::fmt; +/// +/// use bitflags::bitflags; +/// +/// bitflags! { +/// struct Flags: u32 { +/// const A = 0b00000001; +/// const B = 0b00000010; +/// } +/// } +/// +/// impl Flags { +/// pub fn clear(&mut self) { +/// self.bits = 0; // The `bits` field can be accessed from within the +/// // same module where the `bitflags!` macro was invoked. +/// } +/// } +/// +/// impl fmt::Display for Flags { +/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +/// write!(f, "hi!") +/// } +/// } +/// +/// fn main() { +/// let mut flags = Flags::A | Flags::B; +/// flags.clear(); +/// assert!(flags.is_empty()); +/// assert_eq!(format!("{}", flags), "hi!"); +/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); +/// assert_eq!(format!("{:?}", Flags::B), "B"); +/// } +/// ``` +#[macro_export(local_inner_macros)] +macro_rules! bitflags { + ( + $(#[$outer:meta])* + $vis:vis struct $BitFlags:ident: $T:ty { + $( + $(#[$inner:ident $($args:tt)*])* + const $Flag:ident = $value:expr; + )* + } + + $($t:tt)* + ) => { + $(#[$outer])* + #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] + $vis struct $BitFlags { + bits: $T, + } + + __impl_bitflags! { + $BitFlags: $T { + $( + $(#[$inner $($args)*])* + $Flag = $value; + )* + } + } + + bitflags! { + $($t)* + } + }; + () => {}; +} + +// A helper macro to implement the `all` function. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_all_bitflags { + ( + $BitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident = $value:expr; + )+ + } + ) => { + // See `Debug::fmt` for why this approach is taken. + #[allow(non_snake_case)] + trait __BitFlags { + $( + const $Flag: $T = 0; + )+ + } + #[allow(non_snake_case)] + impl __BitFlags for $BitFlags { + $( + __impl_bitflags! { + #[allow(deprecated)] + $(? #[$attr $($args)*])* + const $Flag: $T = Self::$Flag.bits; + } + )+ + } + Self { bits: $(::$Flag)|+ } + }; + ( + $BitFlags:ident: $T:ty { } + ) => { + Self { bits: 0 } + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_bitflags { + ( + $BitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident = $value:expr; + )* + } + ) => { + impl $crate::_core::fmt::Debug for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + // This convoluted approach is to handle #[cfg]-based flag + // omission correctly. For example it needs to support: + // + // #[cfg(unix)] const A: Flag = /* ... */; + // #[cfg(windows)] const B: Flag = /* ... */; + + // Unconditionally define a check for every flag, even disabled + // ones. + #[allow(non_snake_case)] + trait __BitFlags { + $( + #[inline] + fn $Flag(&self) -> bool { false } + )* + } + + // Conditionally override the check for just those flags that + // are not #[cfg]ed away. + #[allow(non_snake_case)] + impl __BitFlags for $BitFlags { + $( + __impl_bitflags! { + #[allow(deprecated)] + #[inline] + $(? #[$attr $($args)*])* + fn $Flag(&self) -> bool { + if Self::$Flag.bits == 0 && self.bits != 0 { + false + } else { + self.bits & Self::$Flag.bits == Self::$Flag.bits + } + } + } + )* + } + + let mut first = true; + $( + if ::$Flag(self) { + if !first { + f.write_str(" | ")?; + } + first = false; + f.write_str($crate::_core::stringify!($Flag))?; + } + )* + let extra_bits = self.bits & !Self::all().bits(); + if extra_bits != 0 { + if !first { + f.write_str(" | ")?; + } + first = false; + f.write_str("0x")?; + $crate::_core::fmt::LowerHex::fmt(&extra_bits, f)?; + } + if first { + f.write_str("(empty)")?; + } + Ok(()) + } + } + impl $crate::_core::fmt::Binary for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::Binary::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::Octal for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::Octal::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::LowerHex for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::LowerHex::fmt(&self.bits, f) + } + } + impl $crate::_core::fmt::UpperHex for $BitFlags { + fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { + $crate::_core::fmt::UpperHex::fmt(&self.bits, f) + } + } + + #[allow(dead_code)] + impl $BitFlags { + $( + $(#[$attr $($args)*])* + pub const $Flag: Self = Self { bits: $value }; + )* + + /// Returns an empty set of flags. + #[inline] + pub const fn empty() -> Self { + Self { bits: 0 } + } + + /// Returns the set containing all flags. + #[inline] + pub const fn all() -> Self { + __impl_all_bitflags! { + $BitFlags: $T { + $( + $(#[$attr $($args)*])* + $Flag = $value; + )* + } + } + } + + /// Returns the raw value of the flags currently stored. + #[inline] + pub const fn bits(&self) -> $T { + self.bits + } + + /// Convert from underlying bit representation, unless that + /// representation contains bits that do not correspond to a flag. + #[inline] + pub const fn from_bits(bits: $T) -> $crate::_core::option::Option { + if (bits & !Self::all().bits()) == 0 { + $crate::_core::option::Option::Some(Self { bits }) + } else { + $crate::_core::option::Option::None + } + } + + /// Convert from underlying bit representation, dropping any bits + /// that do not correspond to flags. + #[inline] + pub const fn from_bits_truncate(bits: $T) -> Self { + Self { bits: bits & Self::all().bits } + } + + /// Convert from underlying bit representation, preserving all + /// bits (even those not corresponding to a defined flag). + /// + /// # Safety + /// + /// The caller of the `bitflags!` macro can chose to allow or + /// disallow extra bits for their bitflags type. + /// + /// The caller of `from_bits_unchecked()` has to ensure that + /// all bits correspond to a defined flag or that extra bits + /// are valid for this bitflags type. + #[inline] + pub const unsafe fn from_bits_unchecked(bits: $T) -> Self { + Self { bits } + } + + /// Returns `true` if no flags are currently stored. + #[inline] + pub const fn is_empty(&self) -> bool { + self.bits() == Self::empty().bits() + } + + /// Returns `true` if all flags are currently set. + #[inline] + pub const fn is_all(&self) -> bool { + Self::all().bits | self.bits == self.bits + } + + /// Returns `true` if there are flags common to both `self` and `other`. + #[inline] + pub const fn intersects(&self, other: Self) -> bool { + !(Self { bits: self.bits & other.bits}).is_empty() + } + + /// Returns `true` if all of the flags in `other` are contained within `self`. + #[inline] + pub const fn contains(&self, other: Self) -> bool { + (self.bits & other.bits) == other.bits + } + + /// Inserts the specified flags in-place. + #[inline] + pub fn insert(&mut self, other: Self) { + self.bits |= other.bits; + } + + /// Removes the specified flags in-place. + #[inline] + pub fn remove(&mut self, other: Self) { + self.bits &= !other.bits; + } + + /// Toggles the specified flags in-place. + #[inline] + pub fn toggle(&mut self, other: Self) { + self.bits ^= other.bits; + } + + /// Inserts or removes the specified flags depending on the passed value. + #[inline] + pub fn set(&mut self, other: Self, value: bool) { + if value { + self.insert(other); + } else { + self.remove(other); + } + } + + /// Returns the intersection between the flags in `self` and + /// `other`. + /// + /// Specifically, the returned set contains only the flags which are + /// present in *both* `self` *and* `other`. + /// + /// This is equivalent to using the `&` operator (e.g. + /// [`ops::BitAnd`]), as in `flags & other`. + /// + /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html + #[inline] + #[must_use] + pub const fn intersection(self, other: Self) -> Self { + Self { bits: self.bits & other.bits } + } + + /// Returns the union of between the flags in `self` and `other`. + /// + /// Specifically, the returned set contains all flags which are + /// present in *either* `self` *or* `other`, including any which are + /// present in both (see [`Self::symmetric_difference`] if that + /// is undesirable). + /// + /// This is equivalent to using the `|` operator (e.g. + /// [`ops::BitOr`]), as in `flags | other`. + /// + /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html + #[inline] + #[must_use] + pub const fn union(self, other: Self) -> Self { + Self { bits: self.bits | other.bits } + } + + /// Returns the difference between the flags in `self` and `other`. + /// + /// Specifically, the returned set contains all flags present in + /// `self`, except for the ones present in `other`. + /// + /// It is also conceptually equivalent to the "bit-clear" operation: + /// `flags & !other` (and this syntax is also supported). + /// + /// This is equivalent to using the `-` operator (e.g. + /// [`ops::Sub`]), as in `flags - other`. + /// + /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html + #[inline] + #[must_use] + pub const fn difference(self, other: Self) -> Self { + Self { bits: self.bits & !other.bits } + } + + /// Returns the [symmetric difference][sym-diff] between the flags + /// in `self` and `other`. + /// + /// Specifically, the returned set contains the flags present which + /// are present in `self` or `other`, but that are not present in + /// both. Equivalently, it contains the flags present in *exactly + /// one* of the sets `self` and `other`. + /// + /// This is equivalent to using the `^` operator (e.g. + /// [`ops::BitXor`]), as in `flags ^ other`. + /// + /// [sym-diff]: https://en.wikipedia.org/wiki/Symmetric_difference + /// [`ops::BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html + #[inline] + #[must_use] + pub const fn symmetric_difference(self, other: Self) -> Self { + Self { bits: self.bits ^ other.bits } + } + + /// Returns the complement of this set of flags. + /// + /// Specifically, the returned set contains all the flags which are + /// not set in `self`, but which are allowed for this type. + /// + /// Alternatively, it can be thought of as the set difference + /// between [`Self::all()`] and `self` (e.g. `Self::all() - self`) + /// + /// This is equivalent to using the `!` operator (e.g. + /// [`ops::Not`]), as in `!flags`. + /// + /// [`Self::all()`]: Self::all + /// [`ops::Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html + #[inline] + #[must_use] + pub const fn complement(self) -> Self { + Self::from_bits_truncate(!self.bits) + } + + } + + impl $crate::_core::ops::BitOr for $BitFlags { + type Output = Self; + + /// Returns the union of the two sets of flags. + #[inline] + fn bitor(self, other: $BitFlags) -> Self { + Self { bits: self.bits | other.bits } + } + } + + impl $crate::_core::ops::BitOrAssign for $BitFlags { + /// Adds the set of flags. + #[inline] + fn bitor_assign(&mut self, other: Self) { + self.bits |= other.bits; + } + } + + impl $crate::_core::ops::BitXor for $BitFlags { + type Output = Self; + + /// Returns the left flags, but with all the right flags toggled. + #[inline] + fn bitxor(self, other: Self) -> Self { + Self { bits: self.bits ^ other.bits } + } + } + + impl $crate::_core::ops::BitXorAssign for $BitFlags { + /// Toggles the set of flags. + #[inline] + fn bitxor_assign(&mut self, other: Self) { + self.bits ^= other.bits; + } + } + + impl $crate::_core::ops::BitAnd for $BitFlags { + type Output = Self; + + /// Returns the intersection between the two sets of flags. + #[inline] + fn bitand(self, other: Self) -> Self { + Self { bits: self.bits & other.bits } + } + } + + impl $crate::_core::ops::BitAndAssign for $BitFlags { + /// Disables all flags disabled in the set. + #[inline] + fn bitand_assign(&mut self, other: Self) { + self.bits &= other.bits; + } + } + + impl $crate::_core::ops::Sub for $BitFlags { + type Output = Self; + + /// Returns the set difference of the two sets of flags. + #[inline] + fn sub(self, other: Self) -> Self { + Self { bits: self.bits & !other.bits } + } + } + + impl $crate::_core::ops::SubAssign for $BitFlags { + /// Disables all flags enabled in the set. + #[inline] + fn sub_assign(&mut self, other: Self) { + self.bits &= !other.bits; + } + } + + impl $crate::_core::ops::Not for $BitFlags { + type Output = Self; + + /// Returns the complement of this set of flags. + #[inline] + fn not(self) -> Self { + Self { bits: !self.bits } & Self::all() + } + } + + impl $crate::_core::iter::Extend<$BitFlags> for $BitFlags { + fn extend>(&mut self, iterator: T) { + for item in iterator { + self.insert(item) + } + } + } + + impl $crate::_core::iter::FromIterator<$BitFlags> for $BitFlags { + fn from_iter>(iterator: T) -> Self { + let mut result = Self::empty(); + result.extend(iterator); + result + } + } + }; + + // Every attribute that the user writes on a const is applied to the + // corresponding const that we generate, but within the implementation of + // Debug and all() we want to ignore everything but #[cfg] attributes. In + // particular, including a #[deprecated] attribute on those items would fail + // to compile. + // https://github.com/bitflags/bitflags/issues/109 + // + // Input: + // + // ? #[cfg(feature = "advanced")] + // ? #[deprecated(note = "Use something else.")] + // ? #[doc = r"High quality documentation."] + // fn f() -> i32 { /* ... */ } + // + // Output: + // + // #[cfg(feature = "advanced")] + // fn f() -> i32 { /* ... */ } + ( + $(#[$filtered:meta])* + ? #[cfg $($cfgargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + fn $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + #[cfg $($cfgargs)*] + $(? #[$rest $($restargs)*])* + fn $($item)* + } + }; + ( + $(#[$filtered:meta])* + // $next != `cfg` + ? #[$next:ident $($nextargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + fn $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + // $next filtered out + $(? #[$rest $($restargs)*])* + fn $($item)* + } + }; + ( + $(#[$filtered:meta])* + fn $($item:tt)* + ) => { + $(#[$filtered])* + fn $($item)* + }; + + // Every attribute that the user writes on a const is applied to the + // corresponding const that we generate, but within the implementation of + // Debug and all() we want to ignore everything but #[cfg] attributes. In + // particular, including a #[deprecated] attribute on those items would fail + // to compile. + // https://github.com/bitflags/bitflags/issues/109 + // + // const version + // + // Input: + // + // ? #[cfg(feature = "advanced")] + // ? #[deprecated(note = "Use something else.")] + // ? #[doc = r"High quality documentation."] + // const f: i32 { /* ... */ } + // + // Output: + // + // #[cfg(feature = "advanced")] + // const f: i32 { /* ... */ } + ( + $(#[$filtered:meta])* + ? #[cfg $($cfgargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + const $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + #[cfg $($cfgargs)*] + $(? #[$rest $($restargs)*])* + const $($item)* + } + }; + ( + $(#[$filtered:meta])* + // $next != `cfg` + ? #[$next:ident $($nextargs:tt)*] + $(? #[$rest:ident $($restargs:tt)*])* + const $($item:tt)* + ) => { + __impl_bitflags! { + $(#[$filtered])* + // $next filtered out + $(? #[$rest $($restargs)*])* + const $($item)* + } + }; + ( + $(#[$filtered:meta])* + const $($item:tt)* + ) => { + $(#[$filtered])* + const $($item)* + }; +} + +#[cfg(feature = "example_generated")] +pub mod example_generated; + +#[cfg(test)] +mod tests { + use std::collections::hash_map::DefaultHasher; + use std::hash::{Hash, Hasher}; + + bitflags! { + #[doc = "> The first principle is that you must not fool yourself — and"] + #[doc = "> you are the easiest person to fool."] + #[doc = "> "] + #[doc = "> - Richard Feynman"] + #[derive(Default)] + struct Flags: u32 { + const A = 0b00000001; + #[doc = " macros are way better at generating code than trans is"] + const B = 0b00000010; + const C = 0b00000100; + #[doc = "* cmr bed"] + #[doc = "* strcat table"] + #[doc = " wait what?"] + const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + } + + struct _CfgFlags: u32 { + #[cfg(unix)] + const _CFG_A = 0b01; + #[cfg(windows)] + const _CFG_B = 0b01; + #[cfg(unix)] + const _CFG_C = Self::_CFG_A.bits | 0b10; + } + + struct AnotherSetOfFlags: i8 { + const ANOTHER_FLAG = -1_i8; + } + + struct LongFlags: u32 { + const LONG_A = 0b1111111111111111; + } + } + + bitflags! { + struct EmptyFlags: u32 { + } + } + + #[test] + fn test_bits() { + assert_eq!(Flags::empty().bits(), 0b00000000); + assert_eq!(Flags::A.bits(), 0b00000001); + assert_eq!(Flags::ABC.bits(), 0b00000111); + + assert_eq!(AnotherSetOfFlags::empty().bits(), 0b00); + assert_eq!(AnotherSetOfFlags::ANOTHER_FLAG.bits(), !0_i8); + + assert_eq!(EmptyFlags::empty().bits(), 0b00000000); + } + + #[test] + fn test_from_bits() { + assert_eq!(Flags::from_bits(0), Some(Flags::empty())); + assert_eq!(Flags::from_bits(0b1), Some(Flags::A)); + assert_eq!(Flags::from_bits(0b10), Some(Flags::B)); + assert_eq!(Flags::from_bits(0b11), Some(Flags::A | Flags::B)); + assert_eq!(Flags::from_bits(0b1000), None); + + assert_eq!( + AnotherSetOfFlags::from_bits(!0_i8), + Some(AnotherSetOfFlags::ANOTHER_FLAG) + ); + + assert_eq!(EmptyFlags::from_bits(0), Some(EmptyFlags::empty())); + assert_eq!(EmptyFlags::from_bits(0b1), None); + } + + #[test] + fn test_from_bits_truncate() { + assert_eq!(Flags::from_bits_truncate(0), Flags::empty()); + assert_eq!(Flags::from_bits_truncate(0b1), Flags::A); + assert_eq!(Flags::from_bits_truncate(0b10), Flags::B); + assert_eq!(Flags::from_bits_truncate(0b11), (Flags::A | Flags::B)); + assert_eq!(Flags::from_bits_truncate(0b1000), Flags::empty()); + assert_eq!(Flags::from_bits_truncate(0b1001), Flags::A); + + assert_eq!( + AnotherSetOfFlags::from_bits_truncate(0_i8), + AnotherSetOfFlags::empty() + ); + + assert_eq!(EmptyFlags::from_bits_truncate(0), EmptyFlags::empty()); + assert_eq!(EmptyFlags::from_bits_truncate(0b1), EmptyFlags::empty()); + } + + #[test] + fn test_from_bits_unchecked() { + let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; + assert_eq!(unsafe { Flags::from_bits_unchecked(0) }, Flags::empty()); + assert_eq!(unsafe { Flags::from_bits_unchecked(0b1) }, Flags::A); + assert_eq!(unsafe { Flags::from_bits_unchecked(0b10) }, Flags::B); + + assert_eq!( + unsafe { Flags::from_bits_unchecked(0b11) }, + (Flags::A | Flags::B) + ); + assert_eq!( + unsafe { Flags::from_bits_unchecked(0b1000) }, + (extra | Flags::empty()) + ); + assert_eq!( + unsafe { Flags::from_bits_unchecked(0b1001) }, + (extra | Flags::A) + ); + + let extra = unsafe { EmptyFlags::from_bits_unchecked(0b1000) }; + assert_eq!( + unsafe { EmptyFlags::from_bits_unchecked(0b1000) }, + (extra | EmptyFlags::empty()) + ); + } + + #[test] + fn test_is_empty() { + assert!(Flags::empty().is_empty()); + assert!(!Flags::A.is_empty()); + assert!(!Flags::ABC.is_empty()); + + assert!(!AnotherSetOfFlags::ANOTHER_FLAG.is_empty()); + + assert!(EmptyFlags::empty().is_empty()); + assert!(EmptyFlags::all().is_empty()); + } + + #[test] + fn test_is_all() { + assert!(Flags::all().is_all()); + assert!(!Flags::A.is_all()); + assert!(Flags::ABC.is_all()); + + let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; + assert!(!extra.is_all()); + assert!(!(Flags::A | extra).is_all()); + assert!((Flags::ABC | extra).is_all()); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.is_all()); + + assert!(EmptyFlags::all().is_all()); + assert!(EmptyFlags::empty().is_all()); + } + + #[test] + fn test_two_empties_do_not_intersect() { + let e1 = Flags::empty(); + let e2 = Flags::empty(); + assert!(!e1.intersects(e2)); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.intersects(AnotherSetOfFlags::ANOTHER_FLAG)); + } + + #[test] + fn test_empty_does_not_intersect_with_full() { + let e1 = Flags::empty(); + let e2 = Flags::ABC; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_disjoint_intersects() { + let e1 = Flags::A; + let e2 = Flags::B; + assert!(!e1.intersects(e2)); + } + + #[test] + fn test_overlapping_intersects() { + let e1 = Flags::A; + let e2 = Flags::A | Flags::B; + assert!(e1.intersects(e2)); + } + + #[test] + fn test_contains() { + let e1 = Flags::A; + let e2 = Flags::A | Flags::B; + assert!(!e1.contains(e2)); + assert!(e2.contains(e1)); + assert!(Flags::ABC.contains(e2)); + + assert!(AnotherSetOfFlags::ANOTHER_FLAG.contains(AnotherSetOfFlags::ANOTHER_FLAG)); + + assert!(EmptyFlags::empty().contains(EmptyFlags::empty())); + } + + #[test] + fn test_insert() { + let mut e1 = Flags::A; + let e2 = Flags::A | Flags::B; + e1.insert(e2); + assert_eq!(e1, e2); + + let mut e3 = AnotherSetOfFlags::empty(); + e3.insert(AnotherSetOfFlags::ANOTHER_FLAG); + assert_eq!(e3, AnotherSetOfFlags::ANOTHER_FLAG); + } + + #[test] + fn test_remove() { + let mut e1 = Flags::A | Flags::B; + let e2 = Flags::A | Flags::C; + e1.remove(e2); + assert_eq!(e1, Flags::B); + + let mut e3 = AnotherSetOfFlags::ANOTHER_FLAG; + e3.remove(AnotherSetOfFlags::ANOTHER_FLAG); + assert_eq!(e3, AnotherSetOfFlags::empty()); + } + + #[test] + fn test_operators() { + let e1 = Flags::A | Flags::C; + let e2 = Flags::B | Flags::C; + assert_eq!((e1 | e2), Flags::ABC); // union + assert_eq!((e1 & e2), Flags::C); // intersection + assert_eq!((e1 - e2), Flags::A); // set difference + assert_eq!(!e2, Flags::A); // set complement + assert_eq!(e1 ^ e2, Flags::A | Flags::B); // toggle + let mut e3 = e1; + e3.toggle(e2); + assert_eq!(e3, Flags::A | Flags::B); + + let mut m4 = AnotherSetOfFlags::empty(); + m4.toggle(AnotherSetOfFlags::empty()); + assert_eq!(m4, AnotherSetOfFlags::empty()); + } + + #[test] + fn test_operators_unchecked() { + let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; + let e1 = Flags::A | Flags::C | extra; + let e2 = Flags::B | Flags::C; + assert_eq!((e1 | e2), (Flags::ABC | extra)); // union + assert_eq!((e1 & e2), Flags::C); // intersection + assert_eq!((e1 - e2), (Flags::A | extra)); // set difference + assert_eq!(!e2, Flags::A); // set complement + assert_eq!(!e1, Flags::B); // set complement + assert_eq!(e1 ^ e2, Flags::A | Flags::B | extra); // toggle + let mut e3 = e1; + e3.toggle(e2); + assert_eq!(e3, Flags::A | Flags::B | extra); + } + + #[test] + fn test_set_ops_basic() { + let ab = Flags::A.union(Flags::B); + let ac = Flags::A.union(Flags::C); + let bc = Flags::B.union(Flags::C); + assert_eq!(ab.bits, 0b011); + assert_eq!(bc.bits, 0b110); + assert_eq!(ac.bits, 0b101); + + assert_eq!(ab, Flags::B.union(Flags::A)); + assert_eq!(ac, Flags::C.union(Flags::A)); + assert_eq!(bc, Flags::C.union(Flags::B)); + + assert_eq!(ac, Flags::A | Flags::C); + assert_eq!(bc, Flags::B | Flags::C); + assert_eq!(ab.union(bc), Flags::ABC); + + assert_eq!(ac, Flags::A | Flags::C); + assert_eq!(bc, Flags::B | Flags::C); + + assert_eq!(ac.union(bc), ac | bc); + assert_eq!(ac.union(bc), Flags::ABC); + assert_eq!(bc.union(ac), Flags::ABC); + + assert_eq!(ac.intersection(bc), ac & bc); + assert_eq!(ac.intersection(bc), Flags::C); + assert_eq!(bc.intersection(ac), Flags::C); + + assert_eq!(ac.difference(bc), ac - bc); + assert_eq!(bc.difference(ac), bc - ac); + assert_eq!(ac.difference(bc), Flags::A); + assert_eq!(bc.difference(ac), Flags::B); + + assert_eq!(bc.complement(), !bc); + assert_eq!(bc.complement(), Flags::A); + assert_eq!(ac.symmetric_difference(bc), Flags::A.union(Flags::B)); + assert_eq!(bc.symmetric_difference(ac), Flags::A.union(Flags::B)); + } + + #[test] + fn test_set_ops_const() { + // These just test that these compile and don't cause use-site panics + // (would be possible if we had some sort of UB) + const INTERSECT: Flags = Flags::all().intersection(Flags::C); + const UNION: Flags = Flags::A.union(Flags::C); + const DIFFERENCE: Flags = Flags::all().difference(Flags::A); + const COMPLEMENT: Flags = Flags::C.complement(); + const SYM_DIFFERENCE: Flags = UNION.symmetric_difference(DIFFERENCE); + assert_eq!(INTERSECT, Flags::C); + assert_eq!(UNION, Flags::A | Flags::C); + assert_eq!(DIFFERENCE, Flags::all() - Flags::A); + assert_eq!(COMPLEMENT, !Flags::C); + assert_eq!(SYM_DIFFERENCE, (Flags::A | Flags::C) ^ (Flags::all() - Flags::A)); + } + + #[test] + fn test_set_ops_unchecked() { + let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; + let e1 = Flags::A.union(Flags::C).union(extra); + let e2 = Flags::B.union(Flags::C); + assert_eq!(e1.bits, 0b1101); + assert_eq!(e1.union(e2), (Flags::ABC | extra)); + assert_eq!(e1.intersection(e2), Flags::C); + assert_eq!(e1.difference(e2), Flags::A | extra); + assert_eq!(e2.difference(e1), Flags::B); + assert_eq!(e2.complement(), Flags::A); + assert_eq!(e1.complement(), Flags::B); + assert_eq!(e1.symmetric_difference(e2), Flags::A | Flags::B | extra); // toggle + } + + #[test] + fn test_set_ops_exhaustive() { + // Define a flag that contains gaps to help exercise edge-cases, + // especially around "unknown" flags (e.g. ones outside of `all()` + // `from_bits_unchecked`). + // - when lhs and rhs both have different sets of unknown flags. + // - unknown flags at both ends, and in the middle + // - cases with "gaps". + bitflags! { + struct Test: u16 { + // Intentionally no `A` + const B = 0b000000010; + // Intentionally no `C` + const D = 0b000001000; + const E = 0b000010000; + const F = 0b000100000; + const G = 0b001000000; + // Intentionally no `H` + const I = 0b100000000; + } + } + let iter_test_flags = + || (0..=0b111_1111_1111).map(|bits| unsafe { Test::from_bits_unchecked(bits) }); + + for a in iter_test_flags() { + assert_eq!( + a.complement(), + Test::from_bits_truncate(!a.bits), + "wrong result: !({:?})", + a, + ); + assert_eq!(a.complement(), !a, "named != op: !({:?})", a); + for b in iter_test_flags() { + // Check that the named operations produce the expected bitwise + // values. + assert_eq!( + a.union(b).bits, + a.bits | b.bits, + "wrong result: `{:?}` | `{:?}`", + a, + b, + ); + assert_eq!( + a.intersection(b).bits, + a.bits & b.bits, + "wrong result: `{:?}` & `{:?}`", + a, + b, + ); + assert_eq!( + a.symmetric_difference(b).bits, + a.bits ^ b.bits, + "wrong result: `{:?}` ^ `{:?}`", + a, + b, + ); + assert_eq!( + a.difference(b).bits, + a.bits & !b.bits, + "wrong result: `{:?}` - `{:?}`", + a, + b, + ); + // Note: Difference is checked as both `a - b` and `b - a` + assert_eq!( + b.difference(a).bits, + b.bits & !a.bits, + "wrong result: `{:?}` - `{:?}`", + b, + a, + ); + // Check that the named set operations are equivalent to the + // bitwise equivalents + assert_eq!(a.union(b), a | b, "named != op: `{:?}` | `{:?}`", a, b,); + assert_eq!( + a.intersection(b), + a & b, + "named != op: `{:?}` & `{:?}`", + a, + b, + ); + assert_eq!( + a.symmetric_difference(b), + a ^ b, + "named != op: `{:?}` ^ `{:?}`", + a, + b, + ); + assert_eq!(a.difference(b), a - b, "named != op: `{:?}` - `{:?}`", a, b,); + // Note: Difference is checked as both `a - b` and `b - a` + assert_eq!(b.difference(a), b - a, "named != op: `{:?}` - `{:?}`", b, a,); + // Verify that the operations which should be symmetric are + // actually symmetric. + assert_eq!(a.union(b), b.union(a), "asymmetry: `{:?}` | `{:?}`", a, b,); + assert_eq!( + a.intersection(b), + b.intersection(a), + "asymmetry: `{:?}` & `{:?}`", + a, + b, + ); + assert_eq!( + a.symmetric_difference(b), + b.symmetric_difference(a), + "asymmetry: `{:?}` ^ `{:?}`", + a, + b, + ); + } + } + } + + #[test] + fn test_set() { + let mut e1 = Flags::A | Flags::C; + e1.set(Flags::B, true); + e1.set(Flags::C, false); + + assert_eq!(e1, Flags::A | Flags::B); + } + + #[test] + fn test_assignment_operators() { + let mut m1 = Flags::empty(); + let e1 = Flags::A | Flags::C; + // union + m1 |= Flags::A; + assert_eq!(m1, Flags::A); + // intersection + m1 &= e1; + assert_eq!(m1, Flags::A); + // set difference + m1 -= m1; + assert_eq!(m1, Flags::empty()); + // toggle + m1 ^= e1; + assert_eq!(m1, e1); + } + + #[test] + fn test_const_fn() { + const _M1: Flags = Flags::empty(); + + const M2: Flags = Flags::A; + assert_eq!(M2, Flags::A); + + const M3: Flags = Flags::C; + assert_eq!(M3, Flags::C); + } + + #[test] + fn test_extend() { + let mut flags; + + flags = Flags::empty(); + flags.extend([].iter().cloned()); + assert_eq!(flags, Flags::empty()); + + flags = Flags::empty(); + flags.extend([Flags::A, Flags::B].iter().cloned()); + assert_eq!(flags, Flags::A | Flags::B); + + flags = Flags::A; + flags.extend([Flags::A, Flags::B].iter().cloned()); + assert_eq!(flags, Flags::A | Flags::B); + + flags = Flags::B; + flags.extend([Flags::A, Flags::ABC].iter().cloned()); + assert_eq!(flags, Flags::ABC); + } + + #[test] + fn test_from_iterator() { + assert_eq!([].iter().cloned().collect::(), Flags::empty()); + assert_eq!( + [Flags::A, Flags::B].iter().cloned().collect::(), + Flags::A | Flags::B + ); + assert_eq!( + [Flags::A, Flags::ABC].iter().cloned().collect::(), + Flags::ABC + ); + } + + #[test] + fn test_lt() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(!(a < b) && !(b < a)); + b = Flags::B; + assert!(a < b); + a = Flags::C; + assert!(!(a < b) && b < a); + b = Flags::C | Flags::B; + assert!(a < b); + } + + #[test] + fn test_ord() { + let mut a = Flags::empty(); + let mut b = Flags::empty(); + + assert!(a <= b && a >= b); + a = Flags::A; + assert!(a > b && a >= b); + assert!(b < a && b <= a); + b = Flags::B; + assert!(b > a && b >= a); + assert!(a < b && a <= b); + } + + fn hash(t: &T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + #[test] + fn test_hash() { + let mut x = Flags::empty(); + let mut y = Flags::empty(); + assert_eq!(hash(&x), hash(&y)); + x = Flags::all(); + y = Flags::ABC; + assert_eq!(hash(&x), hash(&y)); + } + + #[test] + fn test_default() { + assert_eq!(Flags::empty(), Flags::default()); + } + + #[test] + fn test_debug() { + assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); + assert_eq!(format!("{:?}", Flags::empty()), "(empty)"); + assert_eq!(format!("{:?}", Flags::ABC), "A | B | C | ABC"); + let extra = unsafe { Flags::from_bits_unchecked(0xb8) }; + assert_eq!(format!("{:?}", extra), "0xb8"); + assert_eq!(format!("{:?}", Flags::A | extra), "A | 0xb8"); + + assert_eq!( + format!("{:?}", Flags::ABC | extra), + "A | B | C | ABC | 0xb8" + ); + + assert_eq!(format!("{:?}", EmptyFlags::empty()), "(empty)"); + } + + #[test] + fn test_binary() { + assert_eq!(format!("{:b}", Flags::ABC), "111"); + assert_eq!(format!("{:#b}", Flags::ABC), "0b111"); + let extra = unsafe { Flags::from_bits_unchecked(0b1010000) }; + assert_eq!(format!("{:b}", Flags::ABC | extra), "1010111"); + assert_eq!(format!("{:#b}", Flags::ABC | extra), "0b1010111"); + } + + #[test] + fn test_octal() { + assert_eq!(format!("{:o}", LongFlags::LONG_A), "177777"); + assert_eq!(format!("{:#o}", LongFlags::LONG_A), "0o177777"); + let extra = unsafe { LongFlags::from_bits_unchecked(0o5000000) }; + assert_eq!(format!("{:o}", LongFlags::LONG_A | extra), "5177777"); + assert_eq!(format!("{:#o}", LongFlags::LONG_A | extra), "0o5177777"); + } + + #[test] + fn test_lowerhex() { + assert_eq!(format!("{:x}", LongFlags::LONG_A), "ffff"); + assert_eq!(format!("{:#x}", LongFlags::LONG_A), "0xffff"); + let extra = unsafe { LongFlags::from_bits_unchecked(0xe00000) }; + assert_eq!(format!("{:x}", LongFlags::LONG_A | extra), "e0ffff"); + assert_eq!(format!("{:#x}", LongFlags::LONG_A | extra), "0xe0ffff"); + } + + #[test] + fn test_upperhex() { + assert_eq!(format!("{:X}", LongFlags::LONG_A), "FFFF"); + assert_eq!(format!("{:#X}", LongFlags::LONG_A), "0xFFFF"); + let extra = unsafe { LongFlags::from_bits_unchecked(0xe00000) }; + assert_eq!(format!("{:X}", LongFlags::LONG_A | extra), "E0FFFF"); + assert_eq!(format!("{:#X}", LongFlags::LONG_A | extra), "0xE0FFFF"); + } + + mod submodule { + bitflags! { + pub struct PublicFlags: i8 { + const X = 0; + } + + struct PrivateFlags: i8 { + const Y = 0; + } + } + + #[test] + fn test_private() { + let _ = PrivateFlags::Y; + } + } + + #[test] + fn test_public() { + let _ = submodule::PublicFlags::X; + } + + mod t1 { + mod foo { + pub type Bar = i32; + } + + bitflags! { + /// baz + struct Flags: foo::Bar { + const A = 0b00000001; + #[cfg(foo)] + const B = 0b00000010; + #[cfg(foo)] + const C = 0b00000010; + } + } + } + + #[test] + fn test_in_function() { + bitflags! { + struct Flags: u8 { + const A = 1; + #[cfg(any())] // false + const B = 2; + } + } + assert_eq!(Flags::all(), Flags::A); + assert_eq!(format!("{:?}", Flags::A), "A"); + } + + #[test] + fn test_deprecated() { + bitflags! { + pub struct TestFlags: u32 { + #[deprecated(note = "Use something else.")] + const ONE = 1; + } + } + } + + #[test] + fn test_pub_crate() { + mod module { + bitflags! { + pub (crate) struct Test: u8 { + const FOO = 1; + } + } + } + + assert_eq!(module::Test::FOO.bits(), 1); + } + + #[test] + fn test_pub_in_module() { + mod module { + mod submodule { + bitflags! { + // `pub (in super)` means only the module `module` will + // be able to access this. + pub (in super) struct Test: u8 { + const FOO = 1; + } + } + } + + mod test { + // Note: due to `pub (in super)`, + // this cannot be accessed directly by the testing code. + pub(super) fn value() -> u8 { + super::submodule::Test::FOO.bits() + } + } + + pub fn value() -> u8 { + test::value() + } + } + + assert_eq!(module::value(), 1) + } + + #[test] + fn test_zero_value_flags() { + bitflags! { + struct Flags: u32 { + const NONE = 0b0; + const SOME = 0b1; + } + } + + assert!(Flags::empty().contains(Flags::NONE)); + assert!(Flags::SOME.contains(Flags::NONE)); + assert!(Flags::NONE.is_empty()); + + assert_eq!(format!("{:?}", Flags::empty()), "NONE"); + assert_eq!(format!("{:?}", Flags::SOME), "SOME"); + } + + #[test] + fn test_empty_bitflags() { + bitflags! {} + } + + #[test] + fn test_u128_bitflags() { + bitflags! { + struct Flags128: u128 { + const A = 0x0000_0000_0000_0000_0000_0000_0000_0001; + const B = 0x0000_0000_0000_1000_0000_0000_0000_0000; + const C = 0x8000_0000_0000_0000_0000_0000_0000_0000; + const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + } + } + + assert_eq!(Flags128::ABC, Flags128::A | Flags128::B | Flags128::C); + assert_eq!(Flags128::A.bits, 0x0000_0000_0000_0000_0000_0000_0000_0001); + assert_eq!(Flags128::B.bits, 0x0000_0000_0000_1000_0000_0000_0000_0000); + assert_eq!(Flags128::C.bits, 0x8000_0000_0000_0000_0000_0000_0000_0000); + assert_eq!( + Flags128::ABC.bits, + 0x8000_0000_0000_1000_0000_0000_0000_0001 + ); + assert_eq!(format!("{:?}", Flags128::A), "A"); + assert_eq!(format!("{:?}", Flags128::B), "B"); + assert_eq!(format!("{:?}", Flags128::C), "C"); + assert_eq!(format!("{:?}", Flags128::ABC), "A | B | C | ABC"); + } + + #[test] + fn test_serde_bitflags_serialize() { + let flags = SerdeFlags::A | SerdeFlags::B; + + let serialized = serde_json::to_string(&flags).unwrap(); + + assert_eq!(serialized, r#"{"bits":3}"#); + } + + #[test] + fn test_serde_bitflags_deserialize() { + let deserialized: SerdeFlags = serde_json::from_str(r#"{"bits":12}"#).unwrap(); + + let expected = SerdeFlags::C | SerdeFlags::D; + + assert_eq!(deserialized.bits, expected.bits); + } + + #[test] + fn test_serde_bitflags_roundtrip() { + let flags = SerdeFlags::A | SerdeFlags::B; + + let deserialized: SerdeFlags = serde_json::from_str(&serde_json::to_string(&flags).unwrap()).unwrap(); + + assert_eq!(deserialized.bits, flags.bits); + } + + bitflags! { + #[derive(serde::Serialize, serde::Deserialize)] + struct SerdeFlags: u32 { + const A = 1; + const B = 2; + const C = 4; + const D = 8; + } + } +} diff --git a/1.3.2/tests/basic.rs b/1.3.2/tests/basic.rs new file mode 100644 index 0000000..73a52be --- /dev/null +++ b/1.3.2/tests/basic.rs @@ -0,0 +1,20 @@ +#![no_std] + +use bitflags::bitflags; + +bitflags! { + /// baz + struct Flags: u32 { + const A = 0b00000001; + #[doc = "bar"] + const B = 0b00000010; + const C = 0b00000100; + #[doc = "foo"] + const ABC = Flags::A.bits | Flags::B.bits | Flags::C.bits; + } +} + +#[test] +fn basic() { + assert_eq!(Flags::ABC, Flags::A | Flags::B | Flags::C); +} diff --git a/1.3.2/tests/compile-fail/.gitignore b/1.3.2/tests/compile-fail/.gitignore new file mode 100644 index 0000000..4dd9abc --- /dev/null +++ b/1.3.2/tests/compile-fail/.gitignore @@ -0,0 +1 @@ +*.stderr diff --git a/1.3.2/tests/compile-fail/impls/copy.rs b/1.3.2/tests/compile-fail/impls/copy.rs new file mode 100644 index 0000000..38f4822 --- /dev/null +++ b/1.3.2/tests/compile-fail/impls/copy.rs @@ -0,0 +1,10 @@ +use bitflags::bitflags; + +bitflags! { + #[derive(Clone, Copy)] + struct Flags: u32 { + const A = 0b00000001; + } +} + +fn main() {} diff --git a/1.3.2/tests/compile-fail/impls/copy.stderr.beta b/1.3.2/tests/compile-fail/impls/copy.stderr.beta new file mode 100644 index 0000000..0c13aa5 --- /dev/null +++ b/1.3.2/tests/compile-fail/impls/copy.stderr.beta @@ -0,0 +1,27 @@ +error[E0119]: conflicting implementations of trait `std::clone::Clone` for type `Flags` + --> $DIR/copy.rs:3:1 + | +3 | / bitflags! { +4 | | #[derive(Clone, Copy)] + | | ----- first implementation here +5 | | struct Flags: u32 { +6 | | const A = 0b00000001; +7 | | } +8 | | } + | |_^ conflicting implementation for `Flags` + | + = note: this error originates in the derive macro `Clone` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `Flags` + --> $DIR/copy.rs:3:1 + | +3 | / bitflags! { +4 | | #[derive(Clone, Copy)] + | | ---- first implementation here +5 | | struct Flags: u32 { +6 | | const A = 0b00000001; +7 | | } +8 | | } + | |_^ conflicting implementation for `Flags` + | + = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/1.3.2/tests/compile-fail/impls/eq.rs b/1.3.2/tests/compile-fail/impls/eq.rs new file mode 100644 index 0000000..4abbd63 --- /dev/null +++ b/1.3.2/tests/compile-fail/impls/eq.rs @@ -0,0 +1,10 @@ +use bitflags::bitflags; + +bitflags! { + #[derive(PartialEq, Eq)] + struct Flags: u32 { + const A = 0b00000001; + } +} + +fn main() {} diff --git a/1.3.2/tests/compile-fail/impls/eq.stderr.beta b/1.3.2/tests/compile-fail/impls/eq.stderr.beta new file mode 100644 index 0000000..8a1a3b4 --- /dev/null +++ b/1.3.2/tests/compile-fail/impls/eq.stderr.beta @@ -0,0 +1,55 @@ +error[E0119]: conflicting implementations of trait `std::cmp::PartialEq` for type `Flags` + --> $DIR/eq.rs:3:1 + | +3 | / bitflags! { +4 | | #[derive(PartialEq, Eq)] + | | --------- first implementation here +5 | | struct Flags: u32 { +6 | | const A = 0b00000001; +7 | | } +8 | | } + | |_^ conflicting implementation for `Flags` + | + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `std::cmp::Eq` for type `Flags` + --> $DIR/eq.rs:3:1 + | +3 | / bitflags! { +4 | | #[derive(PartialEq, Eq)] + | | -- first implementation here +5 | | struct Flags: u32 { +6 | | const A = 0b00000001; +7 | | } +8 | | } + | |_^ conflicting implementation for `Flags` + | + = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `std::marker::StructuralPartialEq` for type `Flags` + --> $DIR/eq.rs:3:1 + | +3 | / bitflags! { +4 | | #[derive(PartialEq, Eq)] + | | --------- first implementation here +5 | | struct Flags: u32 { +6 | | const A = 0b00000001; +7 | | } +8 | | } + | |_^ conflicting implementation for `Flags` + | + = note: this error originates in the derive macro `PartialEq` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0119]: conflicting implementations of trait `std::marker::StructuralEq` for type `Flags` + --> $DIR/eq.rs:3:1 + | +3 | / bitflags! { +4 | | #[derive(PartialEq, Eq)] + | | -- first implementation here +5 | | struct Flags: u32 { +6 | | const A = 0b00000001; +7 | | } +8 | | } + | |_^ conflicting implementation for `Flags` + | + = note: this error originates in the derive macro `Eq` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/1.3.2/tests/compile-fail/non_integer_base/all_defined.rs b/1.3.2/tests/compile-fail/non_integer_base/all_defined.rs new file mode 100644 index 0000000..c2856b1 --- /dev/null +++ b/1.3.2/tests/compile-fail/non_integer_base/all_defined.rs @@ -0,0 +1,123 @@ +use std::{ + fmt::{ + self, + Debug, + Display, + LowerHex, + UpperHex, + Octal, + Binary, + }, + ops::{ + BitAnd, + BitOr, + BitXor, + BitAndAssign, + BitOrAssign, + BitXorAssign, + Not, + }, +}; + +use bitflags::bitflags; + +// Ideally we'd actually want this to work, but currently need something like `num`'s `Zero` +// With some design work it could be made possible +#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] +struct MyInt(u8); + +impl BitAnd for MyInt { + type Output = Self; + + fn bitand(self, other: Self) -> Self { + MyInt(self.0 & other.0) + } +} + +impl BitOr for MyInt { + type Output = Self; + + fn bitor(self, other: Self) -> Self { + MyInt(self.0 | other.0) + } +} + +impl BitXor for MyInt { + type Output = Self; + + fn bitxor(self, other: Self) -> Self { + MyInt(self.0 ^ other.0) + } +} + +impl BitAndAssign for MyInt { + fn bitand_assign(&mut self, other: Self) { + self.0 &= other.0 + } +} + +impl BitOrAssign for MyInt { + fn bitor_assign(&mut self, other: Self) { + self.0 |= other.0 + } +} + +impl BitXorAssign for MyInt { + fn bitxor_assign(&mut self, other: Self) { + self.0 ^= other.0 + } +} + +impl Debug for MyInt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Debug::fmt(&self.0, f) + } +} + +impl Display for MyInt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +impl LowerHex for MyInt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + LowerHex::fmt(&self.0, f) + } +} + +impl UpperHex for MyInt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + UpperHex::fmt(&self.0, f) + } +} + +impl Octal for MyInt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Octal::fmt(&self.0, f) + } +} + +impl Binary for MyInt { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Binary::fmt(&self.0, f) + } +} + +impl Not for MyInt { + type Output = MyInt; + + fn not(self) -> Self { + MyInt(!self.0) + } +} + +bitflags! { + struct Flags128: MyInt { + const A = MyInt(0b0000_0001u8); + const B = MyInt(0b0000_0010u8); + const C = MyInt(0b0000_0100u8); + } +} + +fn main() {} diff --git a/1.3.2/tests/compile-fail/non_integer_base/all_defined.stderr.beta b/1.3.2/tests/compile-fail/non_integer_base/all_defined.stderr.beta new file mode 100644 index 0000000..1f0fb5c --- /dev/null +++ b/1.3.2/tests/compile-fail/non_integer_base/all_defined.stderr.beta @@ -0,0 +1,27 @@ +error[E0308]: mismatched types + --> $DIR/all_defined.rs:115:1 + | +115 | / bitflags! { +116 | | struct Flags128: MyInt { +117 | | const A = MyInt(0b0000_0001u8); +118 | | const B = MyInt(0b0000_0010u8); +119 | | const C = MyInt(0b0000_0100u8); +120 | | } +121 | | } + | |_^ expected struct `MyInt`, found integer + | + = note: this error originates in the macro `__impl_all_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0308]: mismatched types + --> $DIR/all_defined.rs:115:1 + | +115 | / bitflags! { +116 | | struct Flags128: MyInt { +117 | | const A = MyInt(0b0000_0001u8); +118 | | const B = MyInt(0b0000_0010u8); +119 | | const C = MyInt(0b0000_0100u8); +120 | | } +121 | | } + | |_^ expected struct `MyInt`, found integer + | + = note: this error originates in the macro `__impl_bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/1.3.2/tests/compile-fail/non_integer_base/all_missing.rs b/1.3.2/tests/compile-fail/non_integer_base/all_missing.rs new file mode 100644 index 0000000..fff6b2c --- /dev/null +++ b/1.3.2/tests/compile-fail/non_integer_base/all_missing.rs @@ -0,0 +1,13 @@ +use bitflags::bitflags; + +struct MyInt(u8); + +bitflags! { + struct Flags128: MyInt { + const A = MyInt(0b0000_0001); + const B = MyInt(0b0000_0010); + const C = MyInt(0b0000_0100); + } +} + +fn main() {} diff --git a/1.3.2/tests/compile-fail/non_integer_base/all_missing.stderr.beta b/1.3.2/tests/compile-fail/non_integer_base/all_missing.stderr.beta new file mode 100644 index 0000000..ee95f83 --- /dev/null +++ b/1.3.2/tests/compile-fail/non_integer_base/all_missing.stderr.beta @@ -0,0 +1,13 @@ +error[E0204]: the trait `Copy` may not be implemented for this type + --> $DIR/all_missing.rs:5:1 + | +5 | / bitflags! { +6 | | struct Flags128: MyInt { +7 | | const A = MyInt(0b0000_0001); +8 | | const B = MyInt(0b0000_0010); +9 | | const C = MyInt(0b0000_0100); +10 | | } +11 | | } + | |_^ this field does not implement `Copy` + | + = note: this error originates in the derive macro `Copy` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/1.3.2/tests/compile-fail/visibility/private_field.rs b/1.3.2/tests/compile-fail/visibility/private_field.rs new file mode 100644 index 0000000..a6a3912 --- /dev/null +++ b/1.3.2/tests/compile-fail/visibility/private_field.rs @@ -0,0 +1,13 @@ +mod example { + use bitflags::bitflags; + + bitflags! { + pub struct Flags1: u32 { + const FLAG_A = 0b00000001; + } + } +} + +fn main() { + let flag1 = example::Flags1::FLAG_A.bits; +} diff --git a/1.3.2/tests/compile-fail/visibility/private_field.stderr.beta b/1.3.2/tests/compile-fail/visibility/private_field.stderr.beta new file mode 100644 index 0000000..58a0466 --- /dev/null +++ b/1.3.2/tests/compile-fail/visibility/private_field.stderr.beta @@ -0,0 +1,10 @@ +error[E0616]: field `bits` of struct `Flags1` is private + --> $DIR/private_field.rs:12:41 + | +12 | let flag1 = example::Flags1::FLAG_A.bits; + | ^^^^ private field + | +help: a method `bits` also exists, call it with parentheses + | +12 | let flag1 = example::Flags1::FLAG_A.bits(); + | ^^ diff --git a/1.3.2/tests/compile-fail/visibility/private_flags.rs b/1.3.2/tests/compile-fail/visibility/private_flags.rs new file mode 100644 index 0000000..85a5b18 --- /dev/null +++ b/1.3.2/tests/compile-fail/visibility/private_flags.rs @@ -0,0 +1,18 @@ +mod example { + use bitflags::bitflags; + + bitflags! { + pub struct Flags1: u32 { + const FLAG_A = 0b00000001; + } + + struct Flags2: u32 { + const FLAG_B = 0b00000010; + } + } +} + +fn main() { + let flag1 = example::Flags1::FLAG_A; + let flag2 = example::Flags2::FLAG_B; +} diff --git a/1.3.2/tests/compile-fail/visibility/private_flags.stderr.beta b/1.3.2/tests/compile-fail/visibility/private_flags.stderr.beta new file mode 100644 index 0000000..d23f832 --- /dev/null +++ b/1.3.2/tests/compile-fail/visibility/private_flags.stderr.beta @@ -0,0 +1,18 @@ +error[E0603]: struct `Flags2` is private + --> $DIR/private_flags.rs:17:26 + | +17 | let flag2 = example::Flags2::FLAG_B; + | ^^^^^^ private struct + | +note: the struct `Flags2` is defined here + --> $DIR/private_flags.rs:4:5 + | +4 | / bitflags! { +5 | | pub struct Flags1: u32 { +6 | | const FLAG_A = 0b00000001; +7 | | } +... | +11 | | } +12 | | } + | |_____^ + = note: this error originates in the macro `bitflags` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/1.3.2/tests/compile-fail/visibility/pub_const.rs b/1.3.2/tests/compile-fail/visibility/pub_const.rs new file mode 100644 index 0000000..b90f0ce --- /dev/null +++ b/1.3.2/tests/compile-fail/visibility/pub_const.rs @@ -0,0 +1,9 @@ +use bitflags::bitflags; + +bitflags! { + pub struct Flags1: u32 { + pub const FLAG_A = 0b00000001; + } +} + +fn main() {} diff --git a/1.3.2/tests/compile-fail/visibility/pub_const.stderr.beta b/1.3.2/tests/compile-fail/visibility/pub_const.stderr.beta new file mode 100644 index 0000000..b01122c --- /dev/null +++ b/1.3.2/tests/compile-fail/visibility/pub_const.stderr.beta @@ -0,0 +1,5 @@ +error: no rules expected the token `pub` + --> $DIR/pub_const.rs:5:9 + | +5 | pub const FLAG_A = 0b00000001; + | ^^^ no rules expected this token in macro call diff --git a/1.3.2/tests/compile-pass/impls/convert.rs b/1.3.2/tests/compile-pass/impls/convert.rs new file mode 100644 index 0000000..1f02982 --- /dev/null +++ b/1.3.2/tests/compile-pass/impls/convert.rs @@ -0,0 +1,17 @@ +use bitflags::bitflags; + +bitflags! { + struct Flags: u32 { + const A = 0b00000001; + } +} + +impl From for Flags { + fn from(v: u32) -> Flags { + Flags::from_bits_truncate(v) + } +} + +fn main() { + +} diff --git a/1.3.2/tests/compile-pass/impls/default.rs b/1.3.2/tests/compile-pass/impls/default.rs new file mode 100644 index 0000000..a97b653 --- /dev/null +++ b/1.3.2/tests/compile-pass/impls/default.rs @@ -0,0 +1,10 @@ +use bitflags::bitflags; + +bitflags! { + #[derive(Default)] + struct Flags: u32 { + const A = 0b00000001; + } +} + +fn main() {} diff --git a/1.3.2/tests/compile-pass/impls/inherent_methods.rs b/1.3.2/tests/compile-pass/impls/inherent_methods.rs new file mode 100644 index 0000000..3052c46 --- /dev/null +++ b/1.3.2/tests/compile-pass/impls/inherent_methods.rs @@ -0,0 +1,15 @@ +use bitflags::bitflags; + +bitflags! { + struct Flags: u32 { + const A = 0b00000001; + } +} + +impl Flags { + pub fn new() -> Flags { + Flags::A + } +} + +fn main() {} diff --git a/1.3.2/tests/compile-pass/redefinition/core.rs b/1.3.2/tests/compile-pass/redefinition/core.rs new file mode 100644 index 0000000..4754921 --- /dev/null +++ b/1.3.2/tests/compile-pass/redefinition/core.rs @@ -0,0 +1,14 @@ +use bitflags::bitflags; + +// Checks for possible errors caused by overriding names used by `bitflags!` internally. + +mod core {} +mod _core {} + +bitflags! { + struct Test: u8 { + const A = 1; + } +} + +fn main() {} diff --git a/1.3.2/tests/compile-pass/redefinition/stringify.rs b/1.3.2/tests/compile-pass/redefinition/stringify.rs new file mode 100644 index 0000000..b04f2f6 --- /dev/null +++ b/1.3.2/tests/compile-pass/redefinition/stringify.rs @@ -0,0 +1,19 @@ +use bitflags::bitflags; + +// Checks for possible errors caused by overriding names used by `bitflags!` internally. + +#[allow(unused_macros)] +macro_rules! stringify { + ($($t:tt)*) => { "..." }; +} + +bitflags! { + struct Test: u8 { + const A = 1; + } +} + +fn main() { + // Just make sure we don't call the redefined `stringify` macro + assert_eq!(format!("{:?}", Test::A), "A"); +} diff --git a/1.3.2/tests/compile-pass/repr/c.rs b/1.3.2/tests/compile-pass/repr/c.rs new file mode 100644 index 0000000..6feba36 --- /dev/null +++ b/1.3.2/tests/compile-pass/repr/c.rs @@ -0,0 +1,10 @@ +use bitflags::bitflags; + +bitflags! { + #[repr(C)] + struct Flags: u32 { + const A = 0b00000001; + } +} + +fn main() {} diff --git a/1.3.2/tests/compile-pass/repr/transparent.rs b/1.3.2/tests/compile-pass/repr/transparent.rs new file mode 100644 index 0000000..e38db4d --- /dev/null +++ b/1.3.2/tests/compile-pass/repr/transparent.rs @@ -0,0 +1,10 @@ +use bitflags::bitflags; + +bitflags! { + #[repr(transparent)] + struct Flags: u32 { + const A = 0b00000001; + } +} + +fn main() {} diff --git a/1.3.2/tests/compile-pass/visibility/bits_field.rs b/1.3.2/tests/compile-pass/visibility/bits_field.rs new file mode 100644 index 0000000..33a7967 --- /dev/null +++ b/1.3.2/tests/compile-pass/visibility/bits_field.rs @@ -0,0 +1,11 @@ +use bitflags::bitflags; + +bitflags! { + pub struct Flags1: u32 { + const FLAG_A = 0b00000001; + } +} + +fn main() { + assert_eq!(0b00000001, Flags1::FLAG_A.bits); +} diff --git a/1.3.2/tests/compile-pass/visibility/pub_in.rs b/1.3.2/tests/compile-pass/visibility/pub_in.rs new file mode 100644 index 0000000..c11050e --- /dev/null +++ b/1.3.2/tests/compile-pass/visibility/pub_in.rs @@ -0,0 +1,19 @@ +mod a { + mod b { + use bitflags::bitflags; + + bitflags! { + pub(in crate::a) struct Flags: u32 { + const FLAG_A = 0b00000001; + } + } + } + + pub fn flags() -> u32 { + b::Flags::FLAG_A.bits() + } +} + +fn main() { + assert_eq!(0b00000001, a::flags()); +} diff --git a/1.3.2/tests/compile.rs b/1.3.2/tests/compile.rs new file mode 100644 index 0000000..ed02d01 --- /dev/null +++ b/1.3.2/tests/compile.rs @@ -0,0 +1,63 @@ +use std::{ + fs, + ffi::OsStr, + io, + path::Path, +}; + +use walkdir::WalkDir; + +#[test] +fn fail() { + prepare_stderr_files("tests/compile-fail").unwrap(); + + let t = trybuild::TestCases::new(); + t.compile_fail("tests/compile-fail/**/*.rs"); +} + +#[test] +fn pass() { + let t = trybuild::TestCases::new(); + t.pass("tests/compile-pass/**/*.rs"); +} + +// Compiler messages may change between versions +// We don't want to have to track these too closely for `bitflags`, but +// having some message to check makes sure user-facing errors are sensical. +// +// The approach we use is to run the test on all compilers, but only check stderr +// output on beta (which is the next stable release). We do this by default ignoring +// any `.stderr` files in the `compile-fail` directory, and copying `.stderr.beta` files +// when we happen to be running on a beta compiler. +fn prepare_stderr_files(path: impl AsRef) -> io::Result<()> { + for entry in WalkDir::new(path) { + let entry = entry?; + + if entry.path().extension().and_then(OsStr::to_str) == Some("beta") { + let renamed = entry.path().with_extension(""); + + // Unconditionally remove a corresponding `.stderr` file for a `.stderr.beta` + // file if it exists. On `beta` compilers, we'll recreate it. On other compilers, + // we don't want to end up checking it anyways. + if renamed.exists() { + fs::remove_file(&renamed)?; + } + + rename_beta_stderr(entry.path(), renamed)?; + } + } + + Ok(()) +} + +#[rustversion::beta] +fn rename_beta_stderr(from: impl AsRef, to: impl AsRef) -> io::Result<()> { + fs::copy(from, to)?; + + Ok(()) +} + +#[rustversion::not(beta)] +fn rename_beta_stderr(_: impl AsRef, _: impl AsRef) -> io::Result<()> { + Ok(()) +} diff --git a/Android.bp b/Android.bp index 13c08dd..a6761c1 100644 --- a/Android.bp +++ b/Android.bp @@ -37,71 +37,17 @@ license { ], } -rust_test { - name: "bitflags_test_src_lib", - host_supported: true, - crate_name: "bitflags", - cargo_env_compat: true, - cargo_pkg_version: "1.3.2", - srcs: ["src/lib.rs"], - test_suites: ["general-tests"], - auto_gen_config: true, - test_options: { - unit_test: true, - }, - edition: "2018", - features: ["default"], - rustlibs: [ - "libserde", - "libserde_json", - "libwalkdir", - ], - proc_macros: [ - "librustversion", - "libserde_derive", - ], -} - -rust_test { - name: "bitflags_test_tests_basic", - host_supported: true, - crate_name: "bitflags", - cargo_env_compat: true, - cargo_pkg_version: "1.3.2", - srcs: ["tests/basic.rs"], - test_suites: ["general-tests"], - auto_gen_config: true, - test_options: { - unit_test: true, - }, - edition: "2018", - features: ["default"], - rustlibs: [ - "libbitflags", - "libserde", - "libserde_json", - "libwalkdir", - ], - proc_macros: [ - "librustversion", - "libserde_derive", - ], -} - rust_library { name: "libbitflags", host_supported: true, crate_name: "bitflags", cargo_env_compat: true, - cargo_pkg_version: "1.3.2", + cargo_pkg_version: "2.2.1", srcs: ["src/lib.rs"], - edition: "2018", - features: ["default"], + edition: "2021", apex_available: [ "//apex_available:platform", - "com.android.btservices", - "com.android.compos", - "com.android.virt", + "//apex_available:anyapex", ], product_available: true, vendor_available: true, diff --git a/CHANGELOG.md b/CHANGELOG.md index 12fea16..5c6df58 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,170 @@ +# 2.2.1 + +## What's Changed +* Refactor attribute filtering to apply per-flag by @KodrAus in https://github.com/bitflags/bitflags/pull/345 + +**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.2.0...2.2.1 + +# 2.2.0 + +## What's Changed +* Create SECURITY.md by @KodrAus in https://github.com/bitflags/bitflags/pull/338 +* add docs to describe the behavior of multi-bit flags by @nicholasbishop in https://github.com/bitflags/bitflags/pull/340 +* Add support for bytemuck by @KodrAus in https://github.com/bitflags/bitflags/pull/336 +* Add a top-level macro for filtering attributes by @KodrAus in https://github.com/bitflags/bitflags/pull/341 + +## New Contributors +* @nicholasbishop made their first contribution in https://github.com/bitflags/bitflags/pull/340 + +**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.1.0...2.2.0 + +# 2.1.0 + +## What's Changed +* Add docs for the internal Field0 and examples of formatting/parsing by @KodrAus in https://github.com/bitflags/bitflags/pull/328 +* Add support for arbitrary by @KodrAus in https://github.com/bitflags/bitflags/pull/324 +* Fix up missing docs for consts within consts by @KodrAus in https://github.com/bitflags/bitflags/pull/330 +* Ignore clippy lint in generated code by @Jake-Shadle in https://github.com/bitflags/bitflags/pull/331 + +## New Contributors +* @Jake-Shadle made their first contribution in https://github.com/bitflags/bitflags/pull/331 + +**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.0.2...2.1.0 + +# 2.0.2 + +## What's Changed +* Fix up missing isize and usize Bits impls by @KodrAus in https://github.com/bitflags/bitflags/pull/321 + +**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.0.1...2.0.2 + +# 2.0.1 + +## What's Changed +* Fix up some docs issues by @KodrAus in https://github.com/bitflags/bitflags/pull/309 +* Make empty_flag() const. by @tormeh in https://github.com/bitflags/bitflags/pull/313 +* Fix formatting of multi-bit flags with partial overlap by @KodrAus in https://github.com/bitflags/bitflags/pull/316 + +## New Contributors +* @tormeh made their first contribution in https://github.com/bitflags/bitflags/pull/313 + +**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.0.0...2.0.1 + +# 2.0.0 + +## What's Changed +* Fix a typo and call out MSRV bump by @KodrAus in https://github.com/bitflags/bitflags/pull/259 +* BitFlags trait by @arturoc in https://github.com/bitflags/bitflags/pull/220 +* Add a hidden trait to discourage manual impls of BitFlags by @KodrAus in https://github.com/bitflags/bitflags/pull/261 +* Sanitize `Ok` by @konsumlamm in https://github.com/bitflags/bitflags/pull/266 +* Fix bug in `Debug` implementation by @konsumlamm in https://github.com/bitflags/bitflags/pull/268 +* Fix a typo in the generated documentation by @wackbyte in https://github.com/bitflags/bitflags/pull/271 +* Use SPDX license format by @atouchet in https://github.com/bitflags/bitflags/pull/272 +* serde tests fail in CI by @arturoc in https://github.com/bitflags/bitflags/pull/277 +* Fix beta test output by @KodrAus in https://github.com/bitflags/bitflags/pull/279 +* Add example to the README.md file by @tiaanl in https://github.com/bitflags/bitflags/pull/270 +* Iterator over all the enabled options by @arturoc in https://github.com/bitflags/bitflags/pull/278 +* from_bits_(truncate) fail with composite flags by @arturoc in https://github.com/bitflags/bitflags/pull/276 +* Add more platform coverage to CI by @KodrAus in https://github.com/bitflags/bitflags/pull/280 +* rework the way cfgs are handled by @KodrAus in https://github.com/bitflags/bitflags/pull/281 +* Split generated code into two types by @KodrAus in https://github.com/bitflags/bitflags/pull/282 +* expose bitflags iters using nameable types by @KodrAus in https://github.com/bitflags/bitflags/pull/286 +* Support creating flags from their names by @KodrAus in https://github.com/bitflags/bitflags/pull/287 +* Update README.md by @KodrAus in https://github.com/bitflags/bitflags/pull/288 +* Prepare for 2.0.0-rc.1 release by @KodrAus in https://github.com/bitflags/bitflags/pull/289 +* Add missing "if" to contains doc-comment in traits.rs by @rusty-snake in https://github.com/bitflags/bitflags/pull/291 +* Forbid unsafe_code by @fintelia in https://github.com/bitflags/bitflags/pull/294 +* serde: enable no-std support by @nim65s in https://github.com/bitflags/bitflags/pull/296 +* Add a parser for flags formatted as bar-separated-values by @KodrAus in https://github.com/bitflags/bitflags/pull/297 +* Prepare for 2.0.0-rc.2 release by @KodrAus in https://github.com/bitflags/bitflags/pull/299 +* Use strip_prefix instead of starts_with + slice by @QuinnPainter in https://github.com/bitflags/bitflags/pull/301 +* Fix up some clippy lints by @KodrAus in https://github.com/bitflags/bitflags/pull/302 +* Prepare for 2.0.0-rc.3 release by @KodrAus in https://github.com/bitflags/bitflags/pull/303 +* feat: Add minimum permissions to rust.yml workflow by @gabibguti in https://github.com/bitflags/bitflags/pull/305 + +## New Contributors +* @wackbyte made their first contribution in https://github.com/bitflags/bitflags/pull/271 +* @atouchet made their first contribution in https://github.com/bitflags/bitflags/pull/272 +* @tiaanl made their first contribution in https://github.com/bitflags/bitflags/pull/270 +* @rusty-snake made their first contribution in https://github.com/bitflags/bitflags/pull/291 +* @fintelia made their first contribution in https://github.com/bitflags/bitflags/pull/294 +* @nim65s made their first contribution in https://github.com/bitflags/bitflags/pull/296 +* @QuinnPainter made their first contribution in https://github.com/bitflags/bitflags/pull/301 +* @gabibguti made their first contribution in https://github.com/bitflags/bitflags/pull/305 + +**Full Changelog**: https://github.com/bitflags/bitflags/compare/1.3.2...2.0.0 + +# 2.0.0-rc.3 + +## What's Changed +* Use strip_prefix instead of starts_with + slice by @QuinnPainter in https://github.com/bitflags/bitflags/pull/301 +* Fix up some clippy lints by @KodrAus in https://github.com/bitflags/bitflags/pull/302 + +## New Contributors +* @QuinnPainter made their first contribution in https://github.com/bitflags/bitflags/pull/301 + +**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.0.0-rc.2...2.0.0-rc.3 + +# 2.0.0-rc.2 + +## Changes to `serde` serialization + +**⚠️ NOTE ⚠️** This release changes the default serialization you'll get if you `#[derive(Serialize, Deserialize)]` +on your generated flags types. It will now use a formatted string for human-readable formats and the underlying bits +type for compact formats. + +To keep the old behavior, see the [`bitflags-serde-legacy`](https://github.com/KodrAus/bitflags-serde-legacy) library. + +## What's Changed + +* Add missing "if" to contains doc-comment in traits.rs by @rusty-snake in https://github.com/bitflags/bitflags/pull/291 +* Forbid unsafe_code by @fintelia in https://github.com/bitflags/bitflags/pull/294 +* serde: enable no-std support by @nim65s in https://github.com/bitflags/bitflags/pull/296 +* Add a parser for flags formatted as bar-separated-values by @KodrAus in https://github.com/bitflags/bitflags/pull/297 + +## New Contributors +* @rusty-snake made their first contribution in https://github.com/bitflags/bitflags/pull/291 +* @fintelia made their first contribution in https://github.com/bitflags/bitflags/pull/294 +* @nim65s made their first contribution in https://github.com/bitflags/bitflags/pull/296 + +**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.0.0-rc.1...2.0.0-rc.2 + +# 2.0.0-rc.1 + +This is a big release including a few years worth of work on a new `BitFlags` trait, iteration, and better macro organization for future extensibility. + +## What's Changed +* Fix a typo and call out MSRV bump by @KodrAus in https://github.com/bitflags/bitflags/pull/259 +* BitFlags trait by @arturoc in https://github.com/bitflags/bitflags/pull/220 +* Add a hidden trait to discourage manual impls of BitFlags by @KodrAus in https://github.com/bitflags/bitflags/pull/261 +* Sanitize `Ok` by @konsumlamm in https://github.com/bitflags/bitflags/pull/266 +* Fix bug in `Debug` implementation by @konsumlamm in https://github.com/bitflags/bitflags/pull/268 +* Fix a typo in the generated documentation by @wackbyte in https://github.com/bitflags/bitflags/pull/271 +* Use SPDX license format by @atouchet in https://github.com/bitflags/bitflags/pull/272 +* serde tests fail in CI by @arturoc in https://github.com/bitflags/bitflags/pull/277 +* Fix beta test output by @KodrAus in https://github.com/bitflags/bitflags/pull/279 +* Add example to the README.md file by @tiaanl in https://github.com/bitflags/bitflags/pull/270 +* Iterator over all the enabled options by @arturoc in https://github.com/bitflags/bitflags/pull/278 +* from_bits_(truncate) fail with composite flags by @arturoc in https://github.com/bitflags/bitflags/pull/276 +* Add more platform coverage to CI by @KodrAus in https://github.com/bitflags/bitflags/pull/280 +* rework the way cfgs are handled by @KodrAus in https://github.com/bitflags/bitflags/pull/281 +* Split generated code into two types by @KodrAus in https://github.com/bitflags/bitflags/pull/282 +* expose bitflags iters using nameable types by @KodrAus in https://github.com/bitflags/bitflags/pull/286 +* Support creating flags from their names by @KodrAus in https://github.com/bitflags/bitflags/pull/287 +* Update README.md by @KodrAus in https://github.com/bitflags/bitflags/pull/288 + +## New Contributors +* @wackbyte made their first contribution in https://github.com/bitflags/bitflags/pull/271 +* @atouchet made their first contribution in https://github.com/bitflags/bitflags/pull/272 +* @tiaanl made their first contribution in https://github.com/bitflags/bitflags/pull/270 + +**Full Changelog**: https://github.com/bitflags/bitflags/compare/1.3.2...2.0.0-rc.1 + # 1.3.2 - Allow `non_snake_case` in generated flags types ([#256]) -[#252]: https://github.com/bitflags/bitflags/pull/256 +[#256]: https://github.com/bitflags/bitflags/pull/256 # 1.3.1 @@ -12,6 +174,8 @@ # 1.3.0 (yanked) +**This release bumps the Minimum Supported Rust Version to `1.46.0`** + - Add `#[repr(transparent)]` ([#187]) - End `empty` doc comment with full stop ([#202]) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..5883363 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,9 @@ +# Updating compile-fail test outputs + +`bitflags` uses the `trybuild` crate to integration test its macros. Since Rust error messages change frequently enough that `nightly` builds produce spurious failures, we only check the compiler output in `beta` builds. If you run: + +``` +TRYBUILD=overwrite cargo +beta test --all +``` + +it will run the tests and update the `trybuild` output files. diff --git a/Cargo.toml b/Cargo.toml index 9d54c72..06afeef 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,29 +3,49 @@ # 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 +# to registry (e.g., crates.io) dependencies. # -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) +# 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" +edition = "2021" +rust-version = "1.56.0" name = "bitflags" -version = "1.3.2" +version = "2.2.1" authors = ["The Rust Project Developers"] -exclude = ["bors.toml"] -description = "A macro to generate structures which behave like bitflags.\n" +exclude = [ + "tests", + ".github", +] +description = """ +A macro to generate structures which behave like bitflags. +""" homepage = "https://github.com/bitflags/bitflags" documentation = "https://docs.rs/bitflags" readme = "README.md" -keywords = ["bit", "bitmask", "bitflags", "flags"] +keywords = [ + "bit", + "bitmask", + "bitflags", + "flags", +] categories = ["no-std"] -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" repository = "https://github.com/bitflags/bitflags" + [package.metadata.docs.rs] features = ["example_generated"] + +[dependencies.arbitrary] +version = "1.0" +optional = true + +[dependencies.bytemuck] +version = "1.0" +optional = true + [dependencies.compiler_builtins] version = "0.1.2" optional = true @@ -34,10 +54,21 @@ optional = true version = "1.0.0" optional = true package = "rustc-std-workspace-core" -[dev-dependencies.rustversion] + +[dependencies.serde] version = "1.0" +optional = true +default-features = false + +[dev-dependencies.arbitrary] +version = "1.0" +features = ["derive"] -[dev-dependencies.serde] +[dev-dependencies.bytemuck] +version = "1.0" +features = ["derive"] + +[dev-dependencies.rustversion] version = "1.0" [dev-dependencies.serde_derive] @@ -46,13 +77,16 @@ version = "1.0" [dev-dependencies.serde_json] version = "1.0" -[dev-dependencies.trybuild] +[dev-dependencies.serde_test] version = "1.0" -[dev-dependencies.walkdir] -version = "2.3" +[dev-dependencies.trybuild] +version = "1.0" [features] -default = [] example_generated = [] -rustc-dep-of-std = ["core", "compiler_builtins"] +rustc-dep-of-std = [ + "core", + "compiler_builtins", +] +std = [] diff --git a/Cargo.toml.orig b/Cargo.toml.orig index be9e05a..a239132 100644 --- a/Cargo.toml.orig +++ b/Cargo.toml.orig @@ -3,10 +3,11 @@ name = "bitflags" # NB: When modifying, also modify: # 1. html_root_url in lib.rs # 2. number in readme (for breaking changes) -version = "1.3.2" -edition = "2018" +version = "2.2.1" +edition = "2021" +rust-version = "1.56.0" authors = ["The Rust Project Developers"] -license = "MIT/Apache-2.0" +license = "MIT OR Apache-2.0" keywords = ["bit", "bitmask", "bitflags", "flags"] readme = "README.md" repository = "https://github.com/bitflags/bitflags" @@ -16,22 +17,26 @@ categories = ["no-std"] description = """ A macro to generate structures which behave like bitflags. """ -exclude = ["bors.toml"] +exclude = ["tests", ".github"] [dependencies] -core = { version = '1.0.0', optional = true, package = 'rustc-std-workspace-core' } -compiler_builtins = { version = '0.1.2', optional = true } +serde = { version = "1.0", optional = true, default-features = false } +arbitrary = { version = "1.0", optional = true } +bytemuck = { version = "1.0", optional = true } +core = { version = "1.0.0", optional = true, package = "rustc-std-workspace-core" } +compiler_builtins = { version = "0.1.2", optional = true } [dev-dependencies] trybuild = "1.0" rustversion = "1.0" -walkdir = "2.3" -serde = "1.0" serde_derive = "1.0" serde_json = "1.0" +serde_test = "1.0" +arbitrary = { version = "1.0", features = ["derive"] } +bytemuck = { version = "1.0", features = ["derive"] } [features] -default = [] +std = [] example_generated = [] rustc-dep-of-std = ["core", "compiler_builtins"] diff --git a/METADATA b/METADATA index 0e660ff..a0bd701 100644 --- a/METADATA +++ b/METADATA @@ -1,3 +1,7 @@ +# This project was upgraded with external_updater. +# Usage: tools/external_updater/updater.sh update rust/crates/bitflags +# For more info, check https://cs.android.com/android/platform/superproject/+/master:tools/external_updater/README.md + name: "bitflags" description: "A macro to generate structures which behave like bitflags." third_party { @@ -7,13 +11,13 @@ third_party { } url { type: ARCHIVE - value: "https://static.crates.io/crates/bitflags/bitflags-1.3.2.crate" + value: "https://static.crates.io/crates/bitflags/bitflags-2.2.1.crate" } - version: "1.3.2" + version: "2.2.1" license_type: NOTICE last_upgrade_date { - year: 2021 - month: 9 - day: 22 + year: 2023 + month: 4 + day: 26 } } diff --git a/README.md b/README.md index 0da0f85..f9a5bb4 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,6 @@ bitflags ======== [![Rust](https://github.com/bitflags/bitflags/workflows/Rust/badge.svg)](https://github.com/bitflags/bitflags/actions) -[![Join the chat at https://gitter.im/bitflags/Lobby](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/bitflags/Lobby?utm_source=badge&utm_medium=badge&utm_content=badge) [![Latest version](https://img.shields.io/crates/v/bitflags.svg)](https://crates.io/crates/bitflags) [![Documentation](https://docs.rs/bitflags/badge.svg)](https://docs.rs/bitflags) ![License](https://img.shields.io/crates/l/bitflags.svg) @@ -18,7 +17,7 @@ Add this to your `Cargo.toml`: ```toml [dependencies] -bitflags = "1.3" +bitflags = "2.2.1" ``` and this to your source code: @@ -27,6 +26,35 @@ and this to your source code: use bitflags::bitflags; ``` +## Example + +Generate a flags structure: + +```rust +use bitflags::bitflags; + +// The `bitflags!` macro generates `struct`s that manage a set of flags. +bitflags! { + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + struct Flags: u32 { + const A = 0b00000001; + const B = 0b00000010; + const C = 0b00000100; + const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); + } +} + +fn main() { + let e1 = Flags::A | Flags::C; + let e2 = Flags::B | Flags::C; + assert_eq!((e1 | e2), Flags::ABC); // union + assert_eq!((e1 & e2), Flags::C); // intersection + assert_eq!((e1 - e2), Flags::A); // set difference + assert_eq!(!e2, Flags::A); // set complement +} +``` + ## Rust Version Support -The minimum supported Rust version is 1.46 due to use of associated constants and const functions. +The minimum supported Rust version is documented in the `Cargo.toml` file. +This may be bumped in minor releases as necessary. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..790ac5b --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,13 @@ +# Security Policy + +## Supported Versions + +Security updates are applied only to the latest release. + +## Reporting a Vulnerability + +If you have discovered a security vulnerability in this project, please report it privately. **Do not disclose it as a public issue.** This gives us time to work with you to fix the issue before public exposure, reducing the chance that the exploit will be used before a patch is released. + +Please disclose it at [security advisory](https://github.com/bitflags/bitflags/security/advisories/new). + +This project is maintained by a team of volunteers on a reasonable-effort basis. As such, please give us at least 90 days to work on a fix before public exposure. diff --git a/TEST_MAPPING b/TEST_MAPPING index 0265d92..4624d6d 100644 --- a/TEST_MAPPING +++ b/TEST_MAPPING @@ -74,20 +74,6 @@ "path": "system/security/keystore2/src/crypto" } ], - "presubmit": [ - { - "name": "bitflags_test_src_lib" - }, - { - "name": "bitflags_test_tests_basic" - } - ], - "presubmit-rust": [ - { - "name": "bitflags_test_src_lib" - }, - { - "name": "bitflags_test_tests_basic" - } - ] + "presubmit": [], + "presubmit-rust": [] } diff --git a/benches/parse.rs b/benches/parse.rs new file mode 100644 index 0000000..caa9203 --- /dev/null +++ b/benches/parse.rs @@ -0,0 +1,96 @@ +#![feature(test)] + +extern crate test; + +use std::{ + fmt::{self, Display}, + str::FromStr, +}; + +bitflags::bitflags! { + struct Flags10: u32 { + const A = 0b0000_0000_0000_0001; + const B = 0b0000_0000_0000_0010; + const C = 0b0000_0000_0000_0100; + const D = 0b0000_0000_0000_1000; + const E = 0b0000_0000_0001_0000; + const F = 0b0000_0000_0010_0000; + const G = 0b0000_0000_0100_0000; + const H = 0b0000_0000_1000_0000; + const I = 0b0000_0001_0000_0000; + const J = 0b0000_0010_0000_0000; + } +} + +impl FromStr for Flags10 { + type Err = bitflags::parser::ParseError; + + fn from_str(flags: &str) -> Result { + Ok(Flags10(flags.parse()?)) + } +} + +impl Display for Flags10 { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + Display::fmt(&self.0, f) + } +} + +#[bench] +fn format_flags_1_present(b: &mut test::Bencher) { + b.iter(|| Flags10::J.to_string()) +} + +#[bench] +fn format_flags_5_present(b: &mut test::Bencher) { + b.iter(|| (Flags10::F | Flags10::G | Flags10::H | Flags10::I | Flags10::J).to_string()) +} + +#[bench] +fn format_flags_10_present(b: &mut test::Bencher) { + b.iter(|| { + (Flags10::A + | Flags10::B + | Flags10::C + | Flags10::D + | Flags10::E + | Flags10::F + | Flags10::G + | Flags10::H + | Flags10::I + | Flags10::J) + .to_string() + }) +} + +#[bench] +fn parse_flags_1_10(b: &mut test::Bencher) { + b.iter(|| { + let flags: Flags10 = "J".parse().unwrap(); + flags + }) +} + +#[bench] +fn parse_flags_5_10(b: &mut test::Bencher) { + b.iter(|| { + let flags: Flags10 = "F | G | H | I | J".parse().unwrap(); + flags + }) +} + +#[bench] +fn parse_flags_10_10(b: &mut test::Bencher) { + b.iter(|| { + let flags: Flags10 = "A | B | C | D | E | F | G | H | I | J".parse().unwrap(); + flags + }) +} + +#[bench] +fn parse_flags_1_10_hex(b: &mut test::Bencher) { + b.iter(|| { + let flags: Flags10 = "0xFF".parse().unwrap(); + flags + }) +} diff --git a/cargo2android.json b/cargo2android.json index 73294f5..bc0ef74 100644 --- a/cargo2android.json +++ b/cargo2android.json @@ -1,19 +1,8 @@ { - "apex-available": [ - "//apex_available:platform", - "com.android.btservices", - "com.android.compos", - "com.android.virt" - ], "dependency-blocklist": [ "trybuild" ], "device": true, "min-sdk-version": "29", - "run": true, - "test-blocklist": [ - "tests/compile.rs" - ], - "tests": true, - "vendor-available": true + "run": true } diff --git a/examples/fmt.rs b/examples/fmt.rs new file mode 100644 index 0000000..3bb9b8c --- /dev/null +++ b/examples/fmt.rs @@ -0,0 +1,49 @@ +//! An example of implementing Rust's standard formatting and parsing traits for flags types. + +use core::{fmt, str}; + +fn main() -> Result<(), bitflags::parser::ParseError> { + bitflags::bitflags! { + // You can `#[derive]` the `Debug` trait, but implementing it manually + // can produce output like `A | B` instead of `Flags(A | B)`. + // #[derive(Debug)] + #[derive(PartialEq, Eq)] + pub struct Flags: u32 { + const A = 1; + const B = 2; + const C = 4; + const D = 8; + } + } + + impl fmt::Debug for Flags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.0, f) + } + } + + impl fmt::Display for Flags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } + } + + impl str::FromStr for Flags { + type Err = bitflags::parser::ParseError; + + fn from_str(flags: &str) -> Result { + Ok(Self(flags.parse()?)) + } + } + + let flags = Flags::A | Flags::B; + + println!("{}", flags); + + let formatted = flags.to_string(); + let parsed: Flags = formatted.parse()?; + + assert_eq!(flags, parsed); + + Ok(()) +} diff --git a/examples/serde.rs b/examples/serde.rs new file mode 100644 index 0000000..22eae2d --- /dev/null +++ b/examples/serde.rs @@ -0,0 +1,36 @@ +//! An example of implementing `serde::Serialize` and `serde::Deserialize`. +//! The `#[serde(transparent)]` attribute is recommended to serialize directly +//! to the underlying bits type without wrapping it in a `serde` newtype. + +#[cfg(feature = "serde")] +fn main() { + use serde_derive::*; + + bitflags::bitflags! { + #[derive(Serialize, Deserialize, Debug, PartialEq, Eq)] + #[serde(transparent)] + pub struct Flags: u32 { + const A = 1; + const B = 2; + const C = 4; + const D = 8; + } + } + + let flags = Flags::A | Flags::B; + + let serialized = serde_json::to_string(&flags).unwrap(); + + println!("{:?} -> {}", flags, serialized); + + assert_eq!(serialized, r#""A | B""#); + + let deserialized: Flags = serde_json::from_str(&serialized).unwrap(); + + println!("{} -> {:?}", serialized, flags); + + assert_eq!(deserialized, flags); +} + +#[cfg(not(feature = "serde"))] +fn main() {} diff --git a/patches/std.diff b/patches/std.diff index a34fe97..69d5b01 100644 --- a/patches/std.diff +++ b/patches/std.diff @@ -1,14 +1,14 @@ diff --git a/src/lib.rs b/src/lib.rs -index 935e432..7e87795 100644 +index d28fd87..35eabca 100644 --- a/src/lib.rs +++ b/src/lib.rs -@@ -275,7 +275,8 @@ - //! - //! Users should generally avoid defining a flag with a value of zero. +@@ -420,7 +420,8 @@ + //! For details on exactly what's generated for it, see the [`Field0`](example_generated/struct.Field0.html) + //! example docs. --#![cfg_attr(not(test), no_std)] +-#![cfg_attr(not(any(feature = "std", test)), no_std)] +// ANDROID: Use std to allow building as a dylib. -+#![cfg_attr(not(any(test, android_dylib)), no_std)] - #![doc(html_root_url = "https://docs.rs/bitflags/1.3.2")] ++#![cfg_attr(not(any(feature = "std", test, android_dylib)), no_std)] + #![cfg_attr(not(test), forbid(unsafe_code))] - #[doc(hidden)] + #![doc(html_root_url = "https://docs.rs/bitflags/2.2.1")] diff --git a/src/example_generated.rs b/src/example_generated.rs index cf188d9..b758901 100644 --- a/src/example_generated.rs +++ b/src/example_generated.rs @@ -1,14 +1,50 @@ //! This module shows an example of code generated by the macro. **IT MUST NOT BE USED OUTSIDE THIS //! CRATE**. +//! +//! Usually, when you call the `bitflags!` macro, only the `Flags` type would be visible. In this +//! example, the `Field0`, `Iter`, and `IterRaw` types are also exposed so that you can explore +//! their APIs. The `Field0` type can be accessed as `self.0` on an instance of `Flags`. -bitflags! { +__declare_public_bitflags! { /// This is the same `Flags` struct defined in the [crate level example](../index.html#example). /// Note that this struct is just for documentation purposes only, it must not be used outside /// this crate. - pub struct Flags: u32 { - const A = 0b00000001; - const B = 0b00000010; - const C = 0b00000100; - const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + pub struct Flags; +} + +__declare_internal_bitflags! { + pub struct Field0: u32; + pub struct Iter; + pub struct IterRaw; +} + +__impl_internal_bitflags! { + Field0: u32, Flags, Iter, IterRaw { + A; + B; + C; + ABC; + } +} + +__impl_public_bitflags! { + Flags: u32, Field0, Iter, IterRaw; +} + +__impl_public_bitflags_consts! { + Flags { + /// Field `A`. + /// + /// This flag has the value `0b00000001`. + A = 0b00000001; + /// Field `B`. + /// + /// This flag has the value `0b00000010`. + B = 0b00000010; + /// Field `C`. + /// + /// This flag has the value `0b00000100`. + C = 0b00000100; + ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); } } diff --git a/src/external.rs b/src/external.rs new file mode 100644 index 0000000..6b07ff6 --- /dev/null +++ b/src/external.rs @@ -0,0 +1,260 @@ +//! Conditional trait implementations for external libraries. + +/* +How do I support a new external library? + +Let's say we want to add support for `my_library`. + +First, we define a macro like so: + +```rust +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(feature = "serde")] +macro_rules! __impl_external_bitflags_my_library { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => { + // Implementation goes here + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(not(feature = "my_library"))] +macro_rules! __impl_external_bitflags_my_library { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => {}; +} +``` + +Note that the macro is actually defined twice; once for when the `my_library` feature +is available, and once for when it's not. This is because the `__impl_external_bitflags_my_library` +macro is called in an end-user's library, not in `bitflags`. In an end-user's library we don't +know whether or not a particular feature of `bitflags` is enabled, so we unconditionally call +the macro, where the body of that macro depends on the feature flag. + +Now, we add our macro call to the `__impl_external_bitflags` macro body: + +```rust +__impl_external_bitflags_my_library! { + $InternalBitFlags: $T { + $( + $(#[$attr $($args)*])* + $Flag; + )* + } +} +``` + +What about libraries that _must_ be supported through `#[derive]`? + +In these cases, the attributes will need to be added to the `__declare_internal_bitflags` macro when +the internal type is declared. +*/ + +#[cfg(feature = "serde")] +pub mod serde_support; +#[cfg(feature = "serde")] +pub use serde; + +#[cfg(feature = "arbitrary")] +pub mod arbitrary_support; +#[cfg(feature = "arbitrary")] +pub use arbitrary; + +#[cfg(feature = "bytemuck")] +pub mod bytemuck_support; +#[cfg(feature = "bytemuck")] +pub use bytemuck; + +/// Implements traits from external libraries for the internal bitflags type. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_external_bitflags { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => { + // Any new library traits impls should be added here + // Use `serde` as an example: generate code when the feature is available, + // and a no-op when it isn't + + __impl_external_bitflags_serde! { + $InternalBitFlags: $T { + $( + $(#[$attr $($args)*])* + $Flag; + )* + } + } + + __impl_external_bitflags_arbitrary! { + $InternalBitFlags: $T { + $( + $(#[$attr $($args)*])* + $Flag; + )* + } + } + + __impl_external_bitflags_bytemuck! { + $InternalBitFlags: $T { + $( + $(#[$attr $($args)*])* + $Flag; + )* + } + } + }; +} + +/// Implement `Serialize` and `Deserialize` for the internal bitflags type. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(feature = "serde")] +macro_rules! __impl_external_bitflags_serde { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => { + impl $crate::__private::serde::Serialize for $InternalBitFlags { + fn serialize( + &self, + serializer: S, + ) -> $crate::__private::core::result::Result { + $crate::__private::serde_support::serialize_bits_default::<$InternalBitFlags, $T, S>( + &self, + serializer, + ) + } + } + + impl<'de> $crate::__private::serde::Deserialize<'de> for $InternalBitFlags { + fn deserialize>( + deserializer: D, + ) -> $crate::__private::core::result::Result { + $crate::__private::serde_support::deserialize_bits_default::<$InternalBitFlags, $T, D>( + deserializer, + ) + } + } + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(not(feature = "serde"))] +macro_rules! __impl_external_bitflags_serde { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => {}; +} + +/// Implement `Arbitrary` for the internal bitflags type. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(feature = "arbitrary")] +macro_rules! __impl_external_bitflags_arbitrary { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => { + impl<'a> $crate::__private::arbitrary::Arbitrary<'a> for $InternalBitFlags { + fn arbitrary( + u: &mut $crate::__private::arbitrary::Unstructured<'a>, + ) -> $crate::__private::arbitrary::Result { + Self::from_bits(u.arbitrary()?).ok_or_else(|| $crate::__private::arbitrary::Error::IncorrectFormat) + } + } + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(not(feature = "arbitrary"))] +macro_rules! __impl_external_bitflags_arbitrary { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => {}; +} + +/// Implement `Pod` and `Zeroable` for the internal bitflags type. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(feature = "bytemuck")] +macro_rules! __impl_external_bitflags_bytemuck { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => { + // SAFETY: $InternalBitFlags is guaranteed to have the same ABI as $T, + // and $T implements Pod + unsafe impl $crate::__private::bytemuck::Pod for $InternalBitFlags + where + $T: $crate::__private::bytemuck::Pod, + { + + } + + // SAFETY: $InternalBitFlags is guaranteed to have the same ABI as $T, + // and $T implements Zeroable + unsafe impl $crate::__private::bytemuck::Zeroable for $InternalBitFlags + where + $T: $crate::__private::bytemuck::Zeroable, + { + + } + }; +} + +#[macro_export(local_inner_macros)] +#[doc(hidden)] +#[cfg(not(feature = "bytemuck"))] +macro_rules! __impl_external_bitflags_bytemuck { + ( + $InternalBitFlags:ident: $T:ty { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => {}; +} diff --git a/src/external/arbitrary_support.rs b/src/external/arbitrary_support.rs new file mode 100644 index 0000000..56708f0 --- /dev/null +++ b/src/external/arbitrary_support.rs @@ -0,0 +1,19 @@ +#[cfg(test)] +mod tests { + use arbitrary::Arbitrary; + + bitflags! { + #[derive(Arbitrary)] + struct Color: u32 { + const RED = 0x1; + const GREEN = 0x2; + const BLUE = 0x4; + } + } + + #[test] + fn test_arbitrary() { + let mut unstructured = arbitrary::Unstructured::new(&[0_u8; 256]); + let _color = Color::arbitrary(&mut unstructured); + } +} diff --git a/src/external/bytemuck_support.rs b/src/external/bytemuck_support.rs new file mode 100644 index 0000000..5ab109e --- /dev/null +++ b/src/external/bytemuck_support.rs @@ -0,0 +1,19 @@ +#[cfg(test)] +mod tests { + use bytemuck::{Pod, Zeroable}; + + bitflags! { + #[derive(Pod, Zeroable, Clone, Copy)] + #[repr(transparent)] + struct Color: u32 { + const RED = 0x1; + const GREEN = 0x2; + const BLUE = 0x4; + } + } + + #[test] + fn test_bytemuck() { + assert_eq!(0x1, bytemuck::cast::(Color::RED)); + } +} diff --git a/src/external/serde_support.rs b/src/external/serde_support.rs new file mode 100644 index 0000000..7c202a2 --- /dev/null +++ b/src/external/serde_support.rs @@ -0,0 +1,84 @@ +use core::{fmt, str}; +use serde::{ + de::{Error, Visitor}, + Deserialize, Deserializer, Serialize, Serializer, +}; + +pub fn serialize_bits_default, B: Serialize, S: Serializer>( + flags: &T, + serializer: S, +) -> Result { + // Serialize human-readable flags as a string like `"A | B"` + if serializer.is_human_readable() { + serializer.collect_str(flags) + } + // Serialize non-human-readable flags directly as the underlying bits + else { + flags.as_ref().serialize(serializer) + } +} + +pub fn deserialize_bits_default< + 'de, + T: str::FromStr + From, + B: Deserialize<'de>, + D: Deserializer<'de>, +>( + deserializer: D, +) -> Result +where + ::Err: fmt::Display, +{ + if deserializer.is_human_readable() { + // Deserialize human-readable flags by parsing them from strings like `"A | B"` + struct FlagsVisitor(core::marker::PhantomData); + + impl<'de, T: str::FromStr> Visitor<'de> for FlagsVisitor + where + ::Err: fmt::Display, + { + type Value = T; + + fn expecting(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { + formatter.write_str("a string value of `|` separated flags") + } + + fn visit_str(self, flags: &str) -> Result { + flags.parse().map_err(|e| E::custom(e)) + } + } + + deserializer.deserialize_str(FlagsVisitor(Default::default())) + } else { + // Deserialize non-human-readable flags directly from the underlying bits + let bits = B::deserialize(deserializer)?; + + Ok(bits.into()) + } +} + +#[cfg(test)] +mod tests { + use serde_test::{assert_tokens, Configure, Token::*}; + bitflags! { + #[derive(serde_derive::Serialize, serde_derive::Deserialize, Debug, PartialEq, Eq)] + #[serde(transparent)] + struct SerdeFlags: u32 { + const A = 1; + const B = 2; + const C = 4; + const D = 8; + } + } + + #[test] + fn test_serde_bitflags_default() { + assert_tokens(&SerdeFlags::empty().readable(), &[Str("")]); + + assert_tokens(&SerdeFlags::empty().compact(), &[U32(0)]); + + assert_tokens(&(SerdeFlags::A | SerdeFlags::B).readable(), &[Str("A | B")]); + + assert_tokens(&(SerdeFlags::A | SerdeFlags::B).compact(), &[U32(1 | 2)]); + } +} diff --git a/src/internal.rs b/src/internal.rs new file mode 100644 index 0000000..eca0a30 --- /dev/null +++ b/src/internal.rs @@ -0,0 +1,570 @@ +//! Generate the internal `bitflags`-facing flags type. +//! +//! The code generated here is owned by `bitflags`, but still part of its public API. +//! Changes to the types generated here need to be considered like any other public API change. + +/// Declare the `bitflags`-facing bitflags struct. +/// +/// This type is part of the `bitflags` crate's public API, but not part of the user's. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __declare_internal_bitflags { + ( + $vis:vis struct $InternalBitFlags:ident: $T:ty; + $iter_vis:vis struct $Iter:ident; + $iter_names_vis:vis struct $IterNames:ident; + ) => { + // NOTE: The ABI of this type is _guaranteed_ to be the same as `T` + // This is relied on by some external libraries like `bytemuck` to make + // its `unsafe` trait impls sound. + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + #[repr(transparent)] + $vis struct $InternalBitFlags { + bits: $T, + } + + $iter_vis struct $Iter { + inner: $IterNames, + done: bool, + } + + $iter_names_vis struct $IterNames { + idx: usize, + source: $InternalBitFlags, + state: $InternalBitFlags, + } + }; +} + +/// Implement functions on the private (bitflags-facing) bitflags type. +/// +/// Methods and trait implementations can be freely added here without breaking end-users. +/// If we want to expose new functionality to `#[derive]`, this is the place to do it. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_internal_bitflags { + ( + $InternalBitFlags:ident: $T:ty, $BitFlags:ident, $Iter:ident, $IterNames:ident { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident; + )* + } + ) => { + impl $crate::__private::PublicFlags for $BitFlags { + type Internal = $InternalBitFlags; + } + + impl $crate::__private::core::default::Default for $InternalBitFlags { + #[inline] + fn default() -> Self { + $InternalBitFlags::empty() + } + } + + impl $crate::__private::core::fmt::Debug for $InternalBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter<'_>) -> $crate::__private::core::fmt::Result { + if self.is_empty() { + // If no flags are set then write an empty hex flag to avoid + // writing an empty string. In some contexts, like serialization, + // an empty string is preferrable, but it may be unexpected in + // others for a format not to produce any output. + // + // We can remove this `0x0` and remain compatible with `FromStr`, + // because an empty string will still parse to an empty set of flags, + // just like `0x0` does. + $crate::__private::core::write!(f, "{:#x}", <$T as $crate::__private::Bits>::EMPTY) + } else { + $crate::__private::core::fmt::Display::fmt(self, f) + } + } + } + + impl $crate::__private::core::fmt::Display for $InternalBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter<'_>) -> $crate::__private::core::fmt::Result { + // A formatter for bitflags that produces text output like: + // + // A | B | 0xf6 + // + // The names of set flags are written in a bar-separated-format, + // followed by a hex number of any remaining bits that are set + // but don't correspond to any flags. + + // Iterate over the valid flags + let mut first = true; + let mut iter = self.iter_names(); + for (name, _) in &mut iter { + if !first { + f.write_str(" | ")?; + } + + first = false; + f.write_str(name)?; + } + + // Append any extra bits that correspond to flags to the end of the format + let extra_bits = iter.state.bits(); + if extra_bits != <$T as $crate::__private::Bits>::EMPTY { + if !first { + f.write_str(" | ")?; + } + + $crate::__private::core::write!(f, "{:#x}", extra_bits)?; + } + + $crate::__private::core::fmt::Result::Ok(()) + } + } + + // The impl for `FromStr` should parse anything produced by `Display` + impl $crate::__private::core::str::FromStr for $InternalBitFlags { + type Err = $crate::parser::ParseError; + + fn from_str(s: &str) -> $crate::__private::core::result::Result { + let s = s.trim(); + + let mut parsed_flags = Self::empty(); + + // If the input is empty then return an empty set of flags + if s.is_empty() { + return $crate::__private::core::result::Result::Ok(parsed_flags); + } + + for flag in s.split('|') { + let flag = flag.trim(); + + // If the flag is empty then we've got missing input + if flag.is_empty() { + return $crate::__private::core::result::Result::Err($crate::parser::ParseError::empty_flag()); + } + + // If the flag starts with `0x` then it's a hex number + // Parse it directly to the underlying bits type + let parsed_flag = if let $crate::__private::core::option::Option::Some(flag) = flag.strip_prefix("0x") { + let bits = <$T>::from_str_radix(flag, 16).map_err(|_| $crate::parser::ParseError::invalid_hex_flag(flag))?; + + Self::from_bits_retain(bits) + } + // Otherwise the flag is a name + // The generated flags type will determine whether + // or not it's a valid identifier + else { + Self::from_name(flag).ok_or_else(|| $crate::parser::ParseError::invalid_named_flag(flag))? + }; + + parsed_flags.insert(parsed_flag); + } + + $crate::__private::core::result::Result::Ok(parsed_flags) + } + } + + impl $crate::__private::core::fmt::Binary for $InternalBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + $crate::__private::core::fmt::Binary::fmt(&self.bits(), f) + } + } + + impl $crate::__private::core::fmt::Octal for $InternalBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + $crate::__private::core::fmt::Octal::fmt(&self.bits(), f) + } + } + + impl $crate::__private::core::fmt::LowerHex for $InternalBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + $crate::__private::core::fmt::LowerHex::fmt(&self.bits(), f) + } + } + + impl $crate::__private::core::fmt::UpperHex for $InternalBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + $crate::__private::core::fmt::UpperHex::fmt(&self.bits(), f) + } + } + + impl $InternalBitFlags { + #[inline] + pub const fn empty() -> Self { + Self { bits: <$T as $crate::__private::Bits>::EMPTY } + } + + #[inline] + pub const fn all() -> Self { + Self::from_bits_truncate(<$T as $crate::__private::Bits>::ALL) + } + + #[inline] + pub const fn bits(&self) -> $T { + self.bits + } + + #[inline] + pub fn bits_mut(&mut self) -> &mut $T { + &mut self.bits + } + + #[inline] + pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option { + let truncated = Self::from_bits_truncate(bits).bits; + + if truncated == bits { + $crate::__private::core::option::Option::Some(Self { bits }) + } else { + $crate::__private::core::option::Option::None + } + } + + #[inline] + pub const fn from_bits_truncate(bits: $T) -> Self { + if bits == <$T as $crate::__private::Bits>::EMPTY { + return Self { bits } + } + + let mut truncated = <$T as $crate::__private::Bits>::EMPTY; + + $( + __expr_safe_flags!( + $(#[$attr $($args)*])* + { + if bits & $BitFlags::$Flag.bits() == $BitFlags::$Flag.bits() { + truncated |= $BitFlags::$Flag.bits() + } + } + ); + )* + + Self { bits: truncated } + } + + #[inline] + pub const fn from_bits_retain(bits: $T) -> Self { + Self { bits } + } + + #[inline] + pub fn from_name(name: &str) -> $crate::__private::core::option::Option { + $( + __expr_safe_flags!( + $(#[$attr $($args)*])* + { + if name == $crate::__private::core::stringify!($Flag) { + return $crate::__private::core::option::Option::Some(Self { bits: $BitFlags::$Flag.bits() }); + } + } + ); + )* + + let _ = name; + $crate::__private::core::option::Option::None + } + + #[inline] + pub const fn iter(&self) -> $Iter { + $Iter { + inner: self.iter_names(), + done: false, + } + } + + #[inline] + pub const fn iter_names(&self) -> $IterNames { + $IterNames { + idx: 0, + source: *self, + state: *self, + } + } + + #[inline] + pub const fn is_empty(&self) -> bool { + self.bits == Self::empty().bits + } + + #[inline] + pub const fn is_all(&self) -> bool { + Self::all().bits | self.bits == self.bits + } + + #[inline] + pub const fn intersects(&self, other: Self) -> bool { + !(Self { bits: self.bits & other.bits}).is_empty() + } + + #[inline] + pub const fn contains(&self, other: Self) -> bool { + (self.bits & other.bits) == other.bits + } + + #[inline] + pub fn insert(&mut self, other: Self) { + self.bits |= other.bits; + } + + #[inline] + pub fn remove(&mut self, other: Self) { + self.bits &= !other.bits; + } + + #[inline] + pub fn toggle(&mut self, other: Self) { + self.bits ^= other.bits; + } + + #[inline] + pub fn set(&mut self, other: Self, value: bool) { + if value { + self.insert(other); + } else { + self.remove(other); + } + } + + #[inline] + #[must_use] + pub const fn intersection(self, other: Self) -> Self { + Self { bits: self.bits & other.bits } + } + + #[inline] + #[must_use] + pub const fn union(self, other: Self) -> Self { + Self { bits: self.bits | other.bits } + } + + #[inline] + #[must_use] + pub const fn difference(self, other: Self) -> Self { + Self { bits: self.bits & !other.bits } + } + + #[inline] + #[must_use] + pub const fn symmetric_difference(self, other: Self) -> Self { + Self { bits: self.bits ^ other.bits } + } + + #[inline] + #[must_use] + pub const fn complement(self) -> Self { + Self::from_bits_truncate(!self.bits) + } + } + + impl $crate::__private::core::convert::AsRef<$T> for $InternalBitFlags { + fn as_ref(&self) -> &$T { + &self.bits + } + } + + impl $crate::__private::core::convert::From<$T> for $InternalBitFlags { + fn from(bits: $T) -> Self { + Self::from_bits_retain(bits) + } + } + + impl $crate::__private::core::iter::Iterator for $Iter { + type Item = $BitFlags; + + fn next(&mut self) -> $crate::__private::core::option::Option { + match self.inner.next().map(|(_, value)| value) { + $crate::__private::core::option::Option::Some(value) => $crate::__private::core::option::Option::Some(value), + $crate::__private::core::option::Option::None if !self.done => { + self.done = true; + + // After iterating through valid names, if there are any bits left over + // then return one final value that includes them. This makes `into_iter` + // and `from_iter` roundtrip + if self.inner.state != $InternalBitFlags::empty() { + $crate::__private::core::option::Option::Some($BitFlags::from_bits_retain(self.inner.state.bits())) + } else { + $crate::__private::core::option::Option::None + } + }, + _ => $crate::__private::core::option::Option::None, + } + } + } + + impl $crate::__private::core::iter::Iterator for $IterNames { + type Item = (&'static str, $BitFlags); + + fn next(&mut self) -> $crate::__private::core::option::Option { + const NUM_FLAGS: usize = { + let mut num_flags = 0; + + $( + __expr_safe_flags!( + $(#[$attr $($args)*])* + { + { num_flags += 1; } + } + ); + )* + + num_flags + }; + + const OPTIONS: [$T; NUM_FLAGS] = [ + $( + __expr_safe_flags!( + $(#[$attr $($args)*])* + { + $BitFlags::$Flag.bits() + } + ), + )* + ]; + + const OPTIONS_NAMES: [&'static str; NUM_FLAGS] = [ + $( + __expr_safe_flags!( + $(#[$attr $($args)*])* + { + $crate::__private::core::stringify!($Flag) + } + ), + )* + ]; + + if self.state.is_empty() || NUM_FLAGS == 0 { + $crate::__private::core::option::Option::None + } else { + #[allow(clippy::indexing_slicing)] + for (flag, flag_name) in OPTIONS[self.idx..NUM_FLAGS].iter().copied() + .zip(OPTIONS_NAMES[self.idx..NUM_FLAGS].iter().copied()) + { + self.idx += 1; + + // NOTE: We check whether the flag exists in self, but remove it from + // a different value. This ensure that overlapping flags are handled + // properly. Take the following example: + // + // const A: 0b00000001; + // const B: 0b00000101; + // + // Given the bits 0b00000101, both A and B are set. But if we removed A + // as we encountered it we'd be left with 0b00000100, which doesn't + // correspond to a valid flag on its own. + if self.source.contains($InternalBitFlags { bits: flag }) { + self.state.remove($InternalBitFlags { bits: flag }); + + return $crate::__private::core::option::Option::Some((flag_name, $BitFlags::from_bits_retain(flag))) + } + } + + $crate::__private::core::option::Option::None + } + } + } + }; +} + +/// A macro that processed the input to `bitflags!` and shuffles attributes around +/// based on whether or not they're "expression-safe". +/// +/// This macro is a token-tree muncher that works on 2 levels: +/// +/// For each attribute, we explicitly match on its identifier, like `cfg` to determine +/// whether or not it should be considered expression-safe. +/// +/// If you find yourself with an attribute that should be considered expression-safe +/// and isn't, it can be added here. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __expr_safe_flags { + // Entrypoint: Move all flags and all attributes into `unprocessed` lists + // where they'll be munched one-at-a-time + ( + $(#[$inner:ident $($args:tt)*])* + { $e:expr } + ) => { + __expr_safe_flags! { + expr: { $e }, + attrs: { + // All attributes start here + unprocessed: [$(#[$inner $($args)*])*], + processed: { + // Attributes that are safe on expressions go here + expr: [], + }, + }, + } + }; + // Process the next attribute on the current flag + // `cfg`: The next flag should be propagated to expressions + // NOTE: You can copy this rules block and replace `cfg` with + // your attribute name that should be considered expression-safe + ( + expr: { $e:expr }, + attrs: { + unprocessed: [ + // cfg matched here + #[cfg $($args:tt)*] + $($attrs_rest:tt)* + ], + processed: { + expr: [$($expr:tt)*], + }, + }, + ) => { + __expr_safe_flags! { + expr: { $e }, + attrs: { + unprocessed: [ + $($attrs_rest)* + ], + processed: { + expr: [ + $($expr)* + // cfg added here + #[cfg $($args)*] + ], + }, + }, + } + }; + // Process the next attribute on the current flag + // `$other`: The next flag should not be propagated to expressions + ( + expr: { $e:expr }, + attrs: { + unprocessed: [ + // $other matched here + #[$other:ident $($args:tt)*] + $($attrs_rest:tt)* + ], + processed: { + expr: [$($expr:tt)*], + }, + }, + ) => { + __expr_safe_flags! { + expr: { $e }, + attrs: { + unprocessed: [ + $($attrs_rest)* + ], + processed: { + expr: [ + // $other not added here + $($expr)* + ], + }, + }, + } + }; + // Once all attributes on all flags are processed, generate the actual code + ( + expr: { $e:expr }, + attrs: { + unprocessed: [], + processed: { + expr: [$(#[$expr:ident $($exprargs:tt)*])*], + }, + }, + ) => { + $(#[$expr $($exprargs)*])* + { $e } + } +} diff --git a/src/lib.rs b/src/lib.rs index 7e87795..35eabca 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -8,24 +8,24 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. -//! A typesafe bitmask flag generator useful for sets of C-style bitmask flags. -//! It can be used for creating typesafe wrappers around C APIs. +//! A typesafe bitmask flag generator useful for sets of C-style flags. +//! It can be used for creating ergonomic wrappers around C APIs. //! //! The `bitflags!` macro generates `struct`s that manage a set of flags. The -//! flags should only be defined for integer types, otherwise unexpected type -//! errors may occur at compile time. +//! type of those flags must be some primitive integer. //! -//! # Example +//! # Examples //! //! ``` //! use bitflags::bitflags; //! //! bitflags! { +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; //! const C = 0b00000100; -//! const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +//! const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); //! } //! } //! @@ -42,59 +42,22 @@ //! See [`example_generated::Flags`](./example_generated/struct.Flags.html) for documentation of code //! generated by the above `bitflags!` expansion. //! -//! The generated `struct`s can also be extended with type and trait -//! implementations: -//! -//! ``` -//! use std::fmt; -//! -//! use bitflags::bitflags; -//! -//! bitflags! { -//! struct Flags: u32 { -//! const A = 0b00000001; -//! const B = 0b00000010; -//! } -//! } -//! -//! impl Flags { -//! pub fn clear(&mut self) { -//! self.bits = 0; // The `bits` field can be accessed from within the -//! // same module where the `bitflags!` macro was invoked. -//! } -//! } -//! -//! impl fmt::Display for Flags { -//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -//! write!(f, "hi!") -//! } -//! } -//! -//! fn main() { -//! let mut flags = Flags::A | Flags::B; -//! flags.clear(); -//! assert!(flags.is_empty()); -//! assert_eq!(format!("{}", flags), "hi!"); -//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); -//! assert_eq!(format!("{:?}", Flags::B), "B"); -//! } -//! ``` -//! //! # Visibility //! -//! The generated structs and their associated flag constants are not exported -//! out of the current module by default. A definition can be exported out of -//! the current module by adding `pub` before `struct`: +//! The `bitflags!` macro supports visibility, just like you'd expect when writing a normal +//! Rust `struct`: //! //! ``` //! mod example { //! use bitflags::bitflags; //! //! bitflags! { +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! pub struct Flags1: u32 { //! const A = 0b00000001; //! } //! +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! # pub //! struct Flags2: u32 { //! const B = 0b00000010; @@ -110,19 +73,22 @@ //! //! # Attributes //! -//! Attributes can be attached to the generated `struct`s by placing them -//! before the `struct` keyword. +//! Attributes can be attached to the generated flags types and their constants as normal. //! -//! ## Representations +//! # Representation //! -//! It's valid to add a `#[repr(C)]` or `#[repr(transparent)]` attribute to a type -//! generated by `bitflags!`. In these cases, the type is guaranteed to be a newtype. +//! It's valid to add a `#[repr(C)]` or `#[repr(transparent)]` attribute to a generated flags type. +//! The generated flags type is always guaranteed to be a newtype where its only field has the same +//! ABI as the underlying integer type. +//! +//! In this example, `Flags` has the same ABI as `u32`: //! //! ``` //! use bitflags::bitflags; //! //! bitflags! { //! #[repr(transparent)] +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -131,19 +97,65 @@ //! } //! ``` //! -//! # Trait implementations +//! # Extending +//! +//! Generated flags types belong to you, so you can add trait implementations to them outside +//! of what the `bitflags!` macro gives: +//! +//! ``` +//! use std::fmt; +//! +//! use bitflags::bitflags; +//! +//! bitflags! { +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! } +//! } +//! +//! impl Flags { +//! pub fn clear(&mut self) { +//! *self.0.bits_mut() = 0; +//! } +//! } +//! +//! fn main() { +//! let mut flags = Flags::A | Flags::B; //! -//! The `Copy`, `Clone`, `PartialEq`, `Eq`, `PartialOrd`, `Ord` and `Hash` -//! traits are automatically derived for the `struct`s using the `derive` attribute. -//! Additional traits can be derived by providing an explicit `derive` -//! attribute on `struct`. +//! flags.clear(); +//! assert!(flags.is_empty()); //! -//! The `Extend` and `FromIterator` traits are implemented for the `struct`s, -//! too: `Extend` adds the union of the instances of the `struct` iterated over, -//! while `FromIterator` calculates the union. +//! assert_eq!(format!("{:?}", Flags::A | Flags::B), "Flags(A | B)"); +//! assert_eq!(format!("{:?}", Flags::B), "Flags(B)"); +//! } +//! ``` //! -//! The `Binary`, `Debug`, `LowerHex`, `Octal` and `UpperHex` traits are also -//! implemented by displaying the bits value of the internal struct. +//! # What's implemented by `bitflags!` +//! +//! The `bitflags!` macro adds some trait implementations and inherent methods +//! to generated flags types, but leaves room for you to choose the semantics +//! of others. +//! +//! ## Iterators +//! +//! The following iterator traits are implemented for generated flags types: +//! +//! - `Extend`: adds the union of the instances iterated over. +//! - `FromIterator`: calculates the union. +//! - `IntoIterator`: iterates over set flag values. +//! +//! ## Formatting +//! +//! The following formatting traits are implemented for generated flags types: +//! +//! - `Binary`. +//! - `LowerHex` and `UpperHex`. +//! - `Octal`. +//! +//! Also see the _Debug and Display_ section for details about standard text +//! representations for flags types. //! //! ## Operators //! @@ -155,7 +167,7 @@ //! - `Sub` and `SubAssign`: set difference //! - `Not`: set complement //! -//! # Methods +//! ## Methods //! //! The following methods are defined for the generated `struct`s: //! @@ -167,7 +179,7 @@ //! defined flag //! - `from_bits_truncate`: convert from underlying bit representation, dropping //! any bits that do not correspond to defined flags -//! - `from_bits_unchecked`: convert from underlying bit representation, keeping +//! - `from_bits_retain`: convert from underlying bit representation, keeping //! all bits (even those not corresponding to defined //! flags) //! - `is_empty`: `true` if no flags are currently stored @@ -192,7 +204,18 @@ //! - `complement`: returns a new set of flags, containing all flags which are //! not set in `self`, but which are allowed for this type. //! -//! ## Default +//! # What's not implemented by `bitflags!` +//! +//! Some functionality is not automatically implemented for generated flags types +//! by the `bitflags!` macro, even when it reasonably could be. This is so callers +//! have more freedom to decide on the semantics of their flags types. +//! +//! ## `Clone` and `Copy` +//! +//! Generated flags types are not automatically copyable, even though they can always +//! derive both `Clone` and `Copy`. +//! +//! ## `Default` //! //! The `Default` trait is not automatically implemented for the generated structs. //! @@ -204,7 +227,7 @@ //! //! bitflags! { //! // Results in default value with bits: 0 -//! #[derive(Default)] +//! #[derive(Default, Clone, Copy, Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -224,6 +247,7 @@ //! use bitflags::bitflags; //! //! bitflags! { +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const A = 0b00000001; //! const B = 0b00000010; @@ -244,7 +268,57 @@ //! } //! ``` //! -//! # Zero Flags +//! ## `Debug` and `Display` +//! +//! The `Debug` trait can be derived for a reasonable implementation. This library defines a standard +//! text-based representation for flags that generated flags types can use. For details on the exact +//! grammar, see the [`parser`] module. +//! +//! To support formatting and parsing your generated flags types using that representation, you can implement +//! the standard `Display` and `FromStr` traits in this fashion: +//! +//! ``` +//! use bitflags::bitflags; +//! use std::{fmt, str}; +//! +//! bitflags::bitflags! { +//! pub struct Flags: u32 { +//! const A = 1; +//! const B = 2; +//! const C = 4; +//! const D = 8; +//! } +//! } +//! +//! impl fmt::Debug for Flags { +//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +//! fmt::Debug::fmt(&self.0, f) +//! } +//! } +//! +//! impl fmt::Display for Flags { +//! fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { +//! fmt::Display::fmt(&self.0, f) +//! } +//! } +//! +//! impl str::FromStr for Flags { +//! type Err = bitflags::parser::ParseError; +//! +//! fn from_str(flags: &str) -> Result { +//! Ok(Self(flags.parse()?)) +//! } +//! } +//! ``` +//! +//! ## `PartialEq` and `PartialOrd` +//! +//! Equality and ordering can be derived for a reasonable implementation, or implemented manually +//! for different semantics. +//! +//! # Edge cases +//! +//! ## Zero Flags //! //! Flags with a value equal to zero will have some strange behavior that one should be aware of. //! @@ -252,6 +326,7 @@ //! use bitflags::bitflags; //! //! bitflags! { +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] //! struct Flags: u32 { //! const NONE = 0b00000000; //! const SOME = 0b00000001; @@ -274,15 +349,148 @@ //! ``` //! //! Users should generally avoid defining a flag with a value of zero. +//! +//! ## Multi-bit Flags +//! +//! It is allowed to define a flag with multiple bits set, however such +//! flags are _not_ treated as a set where any of those bits is a valid +//! flag. Instead, each flag is treated as a unit when converting from +//! bits with [`from_bits`] or [`from_bits_truncate`]. +//! +//! ``` +//! use bitflags::bitflags; +//! +//! bitflags! { +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +//! struct Flags: u8 { +//! const F3 = 0b00000011; +//! } +//! } +//! +//! fn main() { +//! // This bit pattern does not set all the bits in `F3`, so it is rejected. +//! assert!(Flags::from_bits(0b00000001).is_none()); +//! assert!(Flags::from_bits_truncate(0b00000001).is_empty()); +//! } +//! ``` +//! +//! [`from_bits`]: BitFlags::from_bits +//! [`from_bits_truncate`]: BitFlags::from_bits_truncate +//! +//! # The `BitFlags` trait +//! +//! This library defines a `BitFlags` trait that's implemented by all generated flags types. +//! The trait makes it possible to work with flags types generically: +//! +//! ``` +//! fn count_unset_flags(flags: &F) -> usize { +//! // Find out how many flags there are in total +//! let total = F::all().iter().count(); +//! +//! // Find out how many flags are set +//! let set = flags.iter().count(); +//! +//! total - set +//! } +//! +//! use bitflags::bitflags; +//! +//! bitflags! { +//! #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +//! struct Flags: u32 { +//! const A = 0b00000001; +//! const B = 0b00000010; +//! const C = 0b00000100; +//! } +//! } +//! +//! assert_eq!(2, count_unset_flags(&Flags::B)); +//! ``` +//! +//! # The internal field +//! +//! This library generates newtypes like: +//! +//! ``` +//! # pub struct Field0; +//! pub struct Flags(Field0); +//! ``` +//! +//! You can freely use methods and trait implementations on this internal field as `.0`. +//! For details on exactly what's generated for it, see the [`Field0`](example_generated/struct.Field0.html) +//! example docs. // ANDROID: Use std to allow building as a dylib. -#![cfg_attr(not(any(test, android_dylib)), no_std)] -#![doc(html_root_url = "https://docs.rs/bitflags/1.3.2")] +#![cfg_attr(not(any(feature = "std", test, android_dylib)), no_std)] +#![cfg_attr(not(test), forbid(unsafe_code))] + +#![doc(html_root_url = "https://docs.rs/bitflags/2.2.1")] + +#[doc(inline)] +pub use traits::BitFlags; + +pub mod parser; +mod traits; #[doc(hidden)] -pub extern crate core as _core; +pub mod __private { + pub use crate::{external::*, traits::*}; + + pub use core; +} + +/* +How does the bitflags crate work? -/// The macro used to generate the flag structures. +This library generates a `struct` in the end-user's crate with a bunch of constants on it that represent flags. +The difference between `bitflags` and a lot of other libraries is that we don't actually control the generated `struct` in the end. +It's part of the end-user's crate, so it belongs to them. That makes it difficult to extend `bitflags` with new functionality +because we could end up breaking valid code that was already written. + +Our solution is to split the type we generate into two: the public struct owned by the end-user, and an internal struct owned by `bitflags` (us). +To give you an example, let's say we had a crate that called `bitflags!`: + +```rust +bitflags! { + pub struct MyFlags: u32 { + const A = 1; + const B = 2; + } +} +``` + +What they'd end up with looks something like this: + +```rust +pub struct MyFlags(::InternalBitFlags); + +const _: () = { + #[repr(transparent)] + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] + pub struct MyInternalBitFlags { + bits: u32, + } + + impl PublicFlags for MyFlags { + type Internal = InternalBitFlags; + } +}; +``` + +If we want to expose something like a new trait impl for generated flags types, we add it to our generated `MyInternalBitFlags`, +and let `#[derive]` on `MyFlags` pick up that implementation, if an end-user chooses to add one. + +The public API is generated in the `__impl_public_flags!` macro, and the internal API is generated in +the `__impl_internal_flags!` macro. + +The macros are split into 3 modules: + +- `public`: where the user-facing flags types are generated. +- `internal`: where the `bitflags`-facing flags types are generated. +- `external`: where external library traits are implemented conditionally. +*/ + +/// The macro used to generate the flag structure. /// /// See the [crate level docs](../bitflags/index.html) for complete documentation. /// @@ -292,22 +500,21 @@ pub extern crate core as _core; /// use bitflags::bitflags; /// /// bitflags! { +/// #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] /// struct Flags: u32 { /// const A = 0b00000001; /// const B = 0b00000010; /// const C = 0b00000100; -/// const ABC = Self::A.bits | Self::B.bits | Self::C.bits; +/// const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); /// } /// } /// -/// fn main() { -/// let e1 = Flags::A | Flags::C; -/// let e2 = Flags::B | Flags::C; -/// assert_eq!((e1 | e2), Flags::ABC); // union -/// assert_eq!((e1 & e2), Flags::C); // intersection -/// assert_eq!((e1 - e2), Flags::A); // set difference -/// assert_eq!(!e2, Flags::A); // set complement -/// } +/// let e1 = Flags::A | Flags::C; +/// let e2 = Flags::B | Flags::C; +/// assert_eq!((e1 | e2), Flags::ABC); // union +/// assert_eq!((e1 & e2), Flags::C); // intersection +/// assert_eq!((e1 - e2), Flags::A); // set difference +/// assert_eq!(!e2, Flags::A); // set complement /// ``` /// /// The generated `struct`s can also be extended with type and trait @@ -319,6 +526,7 @@ pub extern crate core as _core; /// use bitflags::bitflags; /// /// bitflags! { +/// #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] /// struct Flags: u32 { /// const A = 0b00000001; /// const B = 0b00000010; @@ -327,25 +535,17 @@ pub extern crate core as _core; /// /// impl Flags { /// pub fn clear(&mut self) { -/// self.bits = 0; // The `bits` field can be accessed from within the -/// // same module where the `bitflags!` macro was invoked. +/// *self.0.bits_mut() = 0; /// } /// } /// -/// impl fmt::Display for Flags { -/// fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { -/// write!(f, "hi!") -/// } -/// } +/// let mut flags = Flags::A | Flags::B; /// -/// fn main() { -/// let mut flags = Flags::A | Flags::B; -/// flags.clear(); -/// assert!(flags.is_empty()); -/// assert_eq!(format!("{}", flags), "hi!"); -/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); -/// assert_eq!(format!("{:?}", Flags::B), "B"); -/// } +/// flags.clear(); +/// assert!(flags.is_empty()); +/// +/// assert_eq!(format!("{:?}", Flags::A | Flags::B), "Flags(A | B)"); +/// assert_eq!(format!("{:?}", Flags::B), "Flags(B)"); /// ``` #[macro_export(local_inner_macros)] macro_rules! bitflags { @@ -360,592 +560,103 @@ macro_rules! bitflags { $($t:tt)* ) => { - $(#[$outer])* - #[derive(Copy, PartialEq, Eq, Clone, PartialOrd, Ord, Hash)] - $vis struct $BitFlags { - bits: $T, + // Declared in the scope of the `bitflags!` call + // This type appears in the end-user's API + __declare_public_bitflags! { + $(#[$outer])* + $vis struct $BitFlags; } - __impl_bitflags! { - $BitFlags: $T { + // Workaround for: https://github.com/bitflags/bitflags/issues/320 + __impl_public_bitflags_consts! { + $BitFlags { $( $(#[$inner $($args)*])* + #[allow( + dead_code, + deprecated, + unused_attributes, + non_upper_case_globals + )] $Flag = $value; )* } } - bitflags! { - $($t)* - } - }; - () => {}; -} - -// A helper macro to implement the `all` function. -#[macro_export(local_inner_macros)] -#[doc(hidden)] -macro_rules! __impl_all_bitflags { - ( - $BitFlags:ident: $T:ty { - $( - $(#[$attr:ident $($args:tt)*])* - $Flag:ident = $value:expr; - )+ - } - ) => { - // See `Debug::fmt` for why this approach is taken. - #[allow(non_snake_case)] - trait __BitFlags { - $( - const $Flag: $T = 0; - )+ - } - #[allow(non_snake_case)] - impl __BitFlags for $BitFlags { - $( - __impl_bitflags! { - #[allow(deprecated)] - $(? #[$attr $($args)*])* - const $Flag: $T = Self::$Flag.bits; - } - )+ - } - Self { bits: $(::$Flag)|+ } - }; - ( - $BitFlags:ident: $T:ty { } - ) => { - Self { bits: 0 } - }; -} + #[allow( + dead_code, + deprecated, + unused_doc_comments, + unused_attributes, + unused_mut, + unused_imports, + non_upper_case_globals + )] + const _: () = { + // Declared in a "hidden" scope that can't be reached directly + // These types don't appear in the end-user's API + __declare_internal_bitflags! { + $vis struct InternalBitFlags: $T; + $vis struct Iter; + $vis struct IterRaw; + } -#[macro_export(local_inner_macros)] -#[doc(hidden)] -macro_rules! __impl_bitflags { - ( - $BitFlags:ident: $T:ty { - $( - $(#[$attr:ident $($args:tt)*])* - $Flag:ident = $value:expr; - )* - } - ) => { - impl $crate::_core::fmt::Debug for $BitFlags { - fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { - // This convoluted approach is to handle #[cfg]-based flag - // omission correctly. For example it needs to support: - // - // #[cfg(unix)] const A: Flag = /* ... */; - // #[cfg(windows)] const B: Flag = /* ... */; - - // Unconditionally define a check for every flag, even disabled - // ones. - #[allow(non_snake_case)] - trait __BitFlags { + __impl_internal_bitflags! { + InternalBitFlags: $T, $BitFlags, Iter, IterRaw { $( - #[inline] - fn $Flag(&self) -> bool { false } + $(#[$inner $($args)*])* + $Flag; )* } + } - // Conditionally override the check for just those flags that - // are not #[cfg]ed away. - #[allow(non_snake_case)] - impl __BitFlags for $BitFlags { + // This is where new library trait implementations can be added + __impl_external_bitflags! { + InternalBitFlags: $T { $( - __impl_bitflags! { - #[allow(deprecated)] - #[inline] - $(? #[$attr $($args)*])* - fn $Flag(&self) -> bool { - if Self::$Flag.bits == 0 && self.bits != 0 { - false - } else { - self.bits & Self::$Flag.bits == Self::$Flag.bits - } - } - } + $(#[$inner $($args)*])* + $Flag; )* } - - let mut first = true; - $( - if ::$Flag(self) { - if !first { - f.write_str(" | ")?; - } - first = false; - f.write_str($crate::_core::stringify!($Flag))?; - } - )* - let extra_bits = self.bits & !Self::all().bits(); - if extra_bits != 0 { - if !first { - f.write_str(" | ")?; - } - first = false; - f.write_str("0x")?; - $crate::_core::fmt::LowerHex::fmt(&extra_bits, f)?; - } - if first { - f.write_str("(empty)")?; - } - Ok(()) - } - } - impl $crate::_core::fmt::Binary for $BitFlags { - fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { - $crate::_core::fmt::Binary::fmt(&self.bits, f) - } - } - impl $crate::_core::fmt::Octal for $BitFlags { - fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { - $crate::_core::fmt::Octal::fmt(&self.bits, f) } - } - impl $crate::_core::fmt::LowerHex for $BitFlags { - fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { - $crate::_core::fmt::LowerHex::fmt(&self.bits, f) - } - } - impl $crate::_core::fmt::UpperHex for $BitFlags { - fn fmt(&self, f: &mut $crate::_core::fmt::Formatter) -> $crate::_core::fmt::Result { - $crate::_core::fmt::UpperHex::fmt(&self.bits, f) - } - } - #[allow(dead_code)] - impl $BitFlags { - $( - $(#[$attr $($args)*])* - pub const $Flag: Self = Self { bits: $value }; - )* - - /// Returns an empty set of flags. - #[inline] - pub const fn empty() -> Self { - Self { bits: 0 } - } - - /// Returns the set containing all flags. - #[inline] - pub const fn all() -> Self { - __impl_all_bitflags! { - $BitFlags: $T { - $( - $(#[$attr $($args)*])* - $Flag = $value; - )* - } - } - } - - /// Returns the raw value of the flags currently stored. - #[inline] - pub const fn bits(&self) -> $T { - self.bits + __impl_public_bitflags! { + $BitFlags: $T, InternalBitFlags, Iter, IterRaw; } + }; - /// Convert from underlying bit representation, unless that - /// representation contains bits that do not correspond to a flag. - #[inline] - pub const fn from_bits(bits: $T) -> $crate::_core::option::Option { - if (bits & !Self::all().bits()) == 0 { - $crate::_core::option::Option::Some(Self { bits }) - } else { - $crate::_core::option::Option::None - } - } - - /// Convert from underlying bit representation, dropping any bits - /// that do not correspond to flags. - #[inline] - pub const fn from_bits_truncate(bits: $T) -> Self { - Self { bits: bits & Self::all().bits } - } - - /// Convert from underlying bit representation, preserving all - /// bits (even those not corresponding to a defined flag). - /// - /// # Safety - /// - /// The caller of the `bitflags!` macro can chose to allow or - /// disallow extra bits for their bitflags type. - /// - /// The caller of `from_bits_unchecked()` has to ensure that - /// all bits correspond to a defined flag or that extra bits - /// are valid for this bitflags type. - #[inline] - pub const unsafe fn from_bits_unchecked(bits: $T) -> Self { - Self { bits } - } - - /// Returns `true` if no flags are currently stored. - #[inline] - pub const fn is_empty(&self) -> bool { - self.bits() == Self::empty().bits() - } - - /// Returns `true` if all flags are currently set. - #[inline] - pub const fn is_all(&self) -> bool { - Self::all().bits | self.bits == self.bits - } - - /// Returns `true` if there are flags common to both `self` and `other`. - #[inline] - pub const fn intersects(&self, other: Self) -> bool { - !(Self { bits: self.bits & other.bits}).is_empty() - } - - /// Returns `true` if all of the flags in `other` are contained within `self`. - #[inline] - pub const fn contains(&self, other: Self) -> bool { - (self.bits & other.bits) == other.bits - } - - /// Inserts the specified flags in-place. - #[inline] - pub fn insert(&mut self, other: Self) { - self.bits |= other.bits; - } - - /// Removes the specified flags in-place. - #[inline] - pub fn remove(&mut self, other: Self) { - self.bits &= !other.bits; - } - - /// Toggles the specified flags in-place. - #[inline] - pub fn toggle(&mut self, other: Self) { - self.bits ^= other.bits; - } - - /// Inserts or removes the specified flags depending on the passed value. - #[inline] - pub fn set(&mut self, other: Self, value: bool) { - if value { - self.insert(other); - } else { - self.remove(other); - } - } - - /// Returns the intersection between the flags in `self` and - /// `other`. - /// - /// Specifically, the returned set contains only the flags which are - /// present in *both* `self` *and* `other`. - /// - /// This is equivalent to using the `&` operator (e.g. - /// [`ops::BitAnd`]), as in `flags & other`. - /// - /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html - #[inline] - #[must_use] - pub const fn intersection(self, other: Self) -> Self { - Self { bits: self.bits & other.bits } - } - - /// Returns the union of between the flags in `self` and `other`. - /// - /// Specifically, the returned set contains all flags which are - /// present in *either* `self` *or* `other`, including any which are - /// present in both (see [`Self::symmetric_difference`] if that - /// is undesirable). - /// - /// This is equivalent to using the `|` operator (e.g. - /// [`ops::BitOr`]), as in `flags | other`. - /// - /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html - #[inline] - #[must_use] - pub const fn union(self, other: Self) -> Self { - Self { bits: self.bits | other.bits } - } - - /// Returns the difference between the flags in `self` and `other`. - /// - /// Specifically, the returned set contains all flags present in - /// `self`, except for the ones present in `other`. - /// - /// It is also conceptually equivalent to the "bit-clear" operation: - /// `flags & !other` (and this syntax is also supported). - /// - /// This is equivalent to using the `-` operator (e.g. - /// [`ops::Sub`]), as in `flags - other`. - /// - /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html - #[inline] - #[must_use] - pub const fn difference(self, other: Self) -> Self { - Self { bits: self.bits & !other.bits } - } - - /// Returns the [symmetric difference][sym-diff] between the flags - /// in `self` and `other`. - /// - /// Specifically, the returned set contains the flags present which - /// are present in `self` or `other`, but that are not present in - /// both. Equivalently, it contains the flags present in *exactly - /// one* of the sets `self` and `other`. - /// - /// This is equivalent to using the `^` operator (e.g. - /// [`ops::BitXor`]), as in `flags ^ other`. - /// - /// [sym-diff]: https://en.wikipedia.org/wiki/Symmetric_difference - /// [`ops::BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html - #[inline] - #[must_use] - pub const fn symmetric_difference(self, other: Self) -> Self { - Self { bits: self.bits ^ other.bits } - } - - /// Returns the complement of this set of flags. - /// - /// Specifically, the returned set contains all the flags which are - /// not set in `self`, but which are allowed for this type. - /// - /// Alternatively, it can be thought of as the set difference - /// between [`Self::all()`] and `self` (e.g. `Self::all() - self`) - /// - /// This is equivalent to using the `!` operator (e.g. - /// [`ops::Not`]), as in `!flags`. - /// - /// [`Self::all()`]: Self::all - /// [`ops::Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html - #[inline] - #[must_use] - pub const fn complement(self) -> Self { - Self::from_bits_truncate(!self.bits) - } - - } - - impl $crate::_core::ops::BitOr for $BitFlags { - type Output = Self; - - /// Returns the union of the two sets of flags. - #[inline] - fn bitor(self, other: $BitFlags) -> Self { - Self { bits: self.bits | other.bits } - } - } - - impl $crate::_core::ops::BitOrAssign for $BitFlags { - /// Adds the set of flags. - #[inline] - fn bitor_assign(&mut self, other: Self) { - self.bits |= other.bits; - } - } - - impl $crate::_core::ops::BitXor for $BitFlags { - type Output = Self; - - /// Returns the left flags, but with all the right flags toggled. - #[inline] - fn bitxor(self, other: Self) -> Self { - Self { bits: self.bits ^ other.bits } - } - } - - impl $crate::_core::ops::BitXorAssign for $BitFlags { - /// Toggles the set of flags. - #[inline] - fn bitxor_assign(&mut self, other: Self) { - self.bits ^= other.bits; - } - } - - impl $crate::_core::ops::BitAnd for $BitFlags { - type Output = Self; - - /// Returns the intersection between the two sets of flags. - #[inline] - fn bitand(self, other: Self) -> Self { - Self { bits: self.bits & other.bits } - } - } - - impl $crate::_core::ops::BitAndAssign for $BitFlags { - /// Disables all flags disabled in the set. - #[inline] - fn bitand_assign(&mut self, other: Self) { - self.bits &= other.bits; - } - } - - impl $crate::_core::ops::Sub for $BitFlags { - type Output = Self; - - /// Returns the set difference of the two sets of flags. - #[inline] - fn sub(self, other: Self) -> Self { - Self { bits: self.bits & !other.bits } - } - } - - impl $crate::_core::ops::SubAssign for $BitFlags { - /// Disables all flags enabled in the set. - #[inline] - fn sub_assign(&mut self, other: Self) { - self.bits &= !other.bits; - } - } - - impl $crate::_core::ops::Not for $BitFlags { - type Output = Self; - - /// Returns the complement of this set of flags. - #[inline] - fn not(self) -> Self { - Self { bits: !self.bits } & Self::all() - } - } - - impl $crate::_core::iter::Extend<$BitFlags> for $BitFlags { - fn extend>(&mut self, iterator: T) { - for item in iterator { - self.insert(item) - } - } - } - - impl $crate::_core::iter::FromIterator<$BitFlags> for $BitFlags { - fn from_iter>(iterator: T) -> Self { - let mut result = Self::empty(); - result.extend(iterator); - result - } - } - }; - - // Every attribute that the user writes on a const is applied to the - // corresponding const that we generate, but within the implementation of - // Debug and all() we want to ignore everything but #[cfg] attributes. In - // particular, including a #[deprecated] attribute on those items would fail - // to compile. - // https://github.com/bitflags/bitflags/issues/109 - // - // Input: - // - // ? #[cfg(feature = "advanced")] - // ? #[deprecated(note = "Use something else.")] - // ? #[doc = r"High quality documentation."] - // fn f() -> i32 { /* ... */ } - // - // Output: - // - // #[cfg(feature = "advanced")] - // fn f() -> i32 { /* ... */ } - ( - $(#[$filtered:meta])* - ? #[cfg $($cfgargs:tt)*] - $(? #[$rest:ident $($restargs:tt)*])* - fn $($item:tt)* - ) => { - __impl_bitflags! { - $(#[$filtered])* - #[cfg $($cfgargs)*] - $(? #[$rest $($restargs)*])* - fn $($item)* - } - }; - ( - $(#[$filtered:meta])* - // $next != `cfg` - ? #[$next:ident $($nextargs:tt)*] - $(? #[$rest:ident $($restargs:tt)*])* - fn $($item:tt)* - ) => { - __impl_bitflags! { - $(#[$filtered])* - // $next filtered out - $(? #[$rest $($restargs)*])* - fn $($item)* - } - }; - ( - $(#[$filtered:meta])* - fn $($item:tt)* - ) => { - $(#[$filtered])* - fn $($item)* - }; - - // Every attribute that the user writes on a const is applied to the - // corresponding const that we generate, but within the implementation of - // Debug and all() we want to ignore everything but #[cfg] attributes. In - // particular, including a #[deprecated] attribute on those items would fail - // to compile. - // https://github.com/bitflags/bitflags/issues/109 - // - // const version - // - // Input: - // - // ? #[cfg(feature = "advanced")] - // ? #[deprecated(note = "Use something else.")] - // ? #[doc = r"High quality documentation."] - // const f: i32 { /* ... */ } - // - // Output: - // - // #[cfg(feature = "advanced")] - // const f: i32 { /* ... */ } - ( - $(#[$filtered:meta])* - ? #[cfg $($cfgargs:tt)*] - $(? #[$rest:ident $($restargs:tt)*])* - const $($item:tt)* - ) => { - __impl_bitflags! { - $(#[$filtered])* - #[cfg $($cfgargs)*] - $(? #[$rest $($restargs)*])* - const $($item)* - } - }; - ( - $(#[$filtered:meta])* - // $next != `cfg` - ? #[$next:ident $($nextargs:tt)*] - $(? #[$rest:ident $($restargs:tt)*])* - const $($item:tt)* - ) => { - __impl_bitflags! { - $(#[$filtered])* - // $next filtered out - $(? #[$rest $($restargs)*])* - const $($item)* + bitflags! { + $($t)* } }; - ( - $(#[$filtered:meta])* - const $($item:tt)* - ) => { - $(#[$filtered])* - const $($item)* - }; + () => {}; } +#[macro_use] +mod public; +#[macro_use] +mod internal; +#[macro_use] +mod external; + #[cfg(feature = "example_generated")] pub mod example_generated; #[cfg(test)] mod tests { - use std::collections::hash_map::DefaultHasher; - use std::hash::{Hash, Hasher}; + use std::{ + collections::hash_map::DefaultHasher, + fmt, + hash::{Hash, Hasher}, + str, + }; bitflags! { #[doc = "> The first principle is that you must not fool yourself — and"] #[doc = "> you are the easiest person to fool."] #[doc = "> "] #[doc = "> - Richard Feynman"] - #[derive(Default)] + #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct Flags: u32 { const A = 0b00000001; #[doc = " macros are way better at generating code than trans is"] @@ -954,28 +665,56 @@ mod tests { #[doc = "* cmr bed"] #[doc = "* strcat table"] #[doc = " wait what?"] - const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); } + #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct _CfgFlags: u32 { #[cfg(unix)] const _CFG_A = 0b01; #[cfg(windows)] const _CFG_B = 0b01; #[cfg(unix)] - const _CFG_C = Self::_CFG_A.bits | 0b10; + const _CFG_C = Self::_CFG_A.bits() | 0b10; } + #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct AnotherSetOfFlags: i8 { const ANOTHER_FLAG = -1_i8; } + #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct LongFlags: u32 { const LONG_A = 0b1111111111111111; } } bitflags! { + #[derive(Debug, PartialEq, Eq)] + struct FmtFlags: u16 { + const 고양이 = 0b0000_0001; + const 개 = 0b0000_0010; + const 물고기 = 0b0000_0100; + const 물고기_고양이 = Self::고양이.bits() | Self::물고기.bits(); + } + } + + impl str::FromStr for FmtFlags { + type Err = crate::parser::ParseError; + + fn from_str(flags: &str) -> Result { + Ok(Self(flags.parse()?)) + } + } + + impl fmt::Display for FmtFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } + } + + bitflags! { + #[derive(Clone, Copy, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] struct EmptyFlags: u32 { } } @@ -1028,28 +767,19 @@ mod tests { } #[test] - fn test_from_bits_unchecked() { - let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; - assert_eq!(unsafe { Flags::from_bits_unchecked(0) }, Flags::empty()); - assert_eq!(unsafe { Flags::from_bits_unchecked(0b1) }, Flags::A); - assert_eq!(unsafe { Flags::from_bits_unchecked(0b10) }, Flags::B); + fn test_from_bits_retain() { + let extra = Flags::from_bits_retain(0b1000); + assert_eq!(Flags::from_bits_retain(0), Flags::empty()); + assert_eq!(Flags::from_bits_retain(0b1), Flags::A); + assert_eq!(Flags::from_bits_retain(0b10), Flags::B); - assert_eq!( - unsafe { Flags::from_bits_unchecked(0b11) }, - (Flags::A | Flags::B) - ); - assert_eq!( - unsafe { Flags::from_bits_unchecked(0b1000) }, - (extra | Flags::empty()) - ); - assert_eq!( - unsafe { Flags::from_bits_unchecked(0b1001) }, - (extra | Flags::A) - ); + assert_eq!(Flags::from_bits_retain(0b11), (Flags::A | Flags::B)); + assert_eq!(Flags::from_bits_retain(0b1000), (extra | Flags::empty())); + assert_eq!(Flags::from_bits_retain(0b1001), (extra | Flags::A)); - let extra = unsafe { EmptyFlags::from_bits_unchecked(0b1000) }; + let extra = EmptyFlags::from_bits_retain(0b1000); assert_eq!( - unsafe { EmptyFlags::from_bits_unchecked(0b1000) }, + EmptyFlags::from_bits_retain(0b1000), (extra | EmptyFlags::empty()) ); } @@ -1072,7 +802,7 @@ mod tests { assert!(!Flags::A.is_all()); assert!(Flags::ABC.is_all()); - let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; + let extra = Flags::from_bits_retain(0b1000); assert!(!extra.is_all()); assert!(!(Flags::A | extra).is_all()); assert!((Flags::ABC | extra).is_all()); @@ -1170,7 +900,7 @@ mod tests { #[test] fn test_operators_unchecked() { - let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; + let extra = Flags::from_bits_retain(0b1000); let e1 = Flags::A | Flags::C | extra; let e2 = Flags::B | Flags::C; assert_eq!((e1 | e2), (Flags::ABC | extra)); // union @@ -1189,9 +919,9 @@ mod tests { let ab = Flags::A.union(Flags::B); let ac = Flags::A.union(Flags::C); let bc = Flags::B.union(Flags::C); - assert_eq!(ab.bits, 0b011); - assert_eq!(bc.bits, 0b110); - assert_eq!(ac.bits, 0b101); + assert_eq!(ab.bits(), 0b011); + assert_eq!(bc.bits(), 0b110); + assert_eq!(ac.bits(), 0b101); assert_eq!(ab, Flags::B.union(Flags::A)); assert_eq!(ac, Flags::C.union(Flags::A)); @@ -1236,15 +966,18 @@ mod tests { assert_eq!(UNION, Flags::A | Flags::C); assert_eq!(DIFFERENCE, Flags::all() - Flags::A); assert_eq!(COMPLEMENT, !Flags::C); - assert_eq!(SYM_DIFFERENCE, (Flags::A | Flags::C) ^ (Flags::all() - Flags::A)); + assert_eq!( + SYM_DIFFERENCE, + (Flags::A | Flags::C) ^ (Flags::all() - Flags::A) + ); } #[test] fn test_set_ops_unchecked() { - let extra = unsafe { Flags::from_bits_unchecked(0b1000) }; + let extra = Flags::from_bits_retain(0b1000); let e1 = Flags::A.union(Flags::C).union(extra); let e2 = Flags::B.union(Flags::C); - assert_eq!(e1.bits, 0b1101); + assert_eq!(e1.bits(), 0b1101); assert_eq!(e1.union(e2), (Flags::ABC | extra)); assert_eq!(e1.intersection(e2), Flags::C); assert_eq!(e1.difference(e2), Flags::A | extra); @@ -1258,11 +991,12 @@ mod tests { fn test_set_ops_exhaustive() { // Define a flag that contains gaps to help exercise edge-cases, // especially around "unknown" flags (e.g. ones outside of `all()` - // `from_bits_unchecked`). + // `from_bits_retain`). // - when lhs and rhs both have different sets of unknown flags. // - unknown flags at both ends, and in the middle // - cases with "gaps". bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Test: u16 { // Intentionally no `A` const B = 0b000000010; @@ -1275,13 +1009,12 @@ mod tests { const I = 0b100000000; } } - let iter_test_flags = - || (0..=0b111_1111_1111).map(|bits| unsafe { Test::from_bits_unchecked(bits) }); + let iter_test_flags = || (0..=0b111_1111_1111).map(|bits| Test::from_bits_retain(bits)); for a in iter_test_flags() { assert_eq!( a.complement(), - Test::from_bits_truncate(!a.bits), + Test::from_bits_truncate(!a.bits()), "wrong result: !({:?})", a, ); @@ -1290,37 +1023,37 @@ mod tests { // Check that the named operations produce the expected bitwise // values. assert_eq!( - a.union(b).bits, - a.bits | b.bits, + a.union(b).bits(), + a.bits() | b.bits(), "wrong result: `{:?}` | `{:?}`", a, b, ); assert_eq!( - a.intersection(b).bits, - a.bits & b.bits, + a.intersection(b).bits(), + a.bits() & b.bits(), "wrong result: `{:?}` & `{:?}`", a, b, ); assert_eq!( - a.symmetric_difference(b).bits, - a.bits ^ b.bits, + a.symmetric_difference(b).bits(), + a.bits() ^ b.bits(), "wrong result: `{:?}` ^ `{:?}`", a, b, ); assert_eq!( - a.difference(b).bits, - a.bits & !b.bits, + a.difference(b).bits(), + a.bits() & !b.bits(), "wrong result: `{:?}` - `{:?}`", a, b, ); // Note: Difference is checked as both `a - b` and `b - a` assert_eq!( - b.difference(a).bits, - b.bits & !a.bits, + b.difference(a).bits(), + b.bits() & !a.bits(), "wrong result: `{:?}` - `{:?}`", b, a, @@ -1489,26 +1222,108 @@ mod tests { #[test] fn test_debug() { - assert_eq!(format!("{:?}", Flags::A | Flags::B), "A | B"); - assert_eq!(format!("{:?}", Flags::empty()), "(empty)"); - assert_eq!(format!("{:?}", Flags::ABC), "A | B | C | ABC"); - let extra = unsafe { Flags::from_bits_unchecked(0xb8) }; - assert_eq!(format!("{:?}", extra), "0xb8"); - assert_eq!(format!("{:?}", Flags::A | extra), "A | 0xb8"); + assert_eq!(format!("{:?}", Flags::A | Flags::B), "Flags(A | B)"); + assert_eq!(format!("{:?}", Flags::empty()), "Flags(0x0)"); + assert_eq!(format!("{:?}", Flags::ABC), "Flags(A | B | C)"); + + let extra = Flags::from_bits_retain(0xb8); + + assert_eq!(format!("{:?}", extra), "Flags(0xb8)"); + assert_eq!(format!("{:?}", Flags::A | extra), "Flags(A | 0xb8)"); assert_eq!( format!("{:?}", Flags::ABC | extra), - "A | B | C | ABC | 0xb8" + "Flags(A | B | C | ABC | 0xb8)" ); - assert_eq!(format!("{:?}", EmptyFlags::empty()), "(empty)"); + assert_eq!(format!("{:?}", EmptyFlags::empty()), "EmptyFlags(0x0)"); + } + + #[test] + fn test_display_from_str_roundtrip() { + fn format_parse_case(flags: T) where ::Err: fmt::Display { + assert_eq!(flags, { + match flags.to_string().parse::() { + Ok(flags) => flags, + Err(e) => panic!("failed to parse `{}`: {}", flags, e), + } + }); + } + + fn parse_case(expected: T, flags: &str) where ::Err: fmt::Display + fmt::Debug { + assert_eq!(expected, flags.parse::().unwrap()); + } + + bitflags! { + #[derive(Debug, Eq, PartialEq)] + pub struct MultiBitFmtFlags: u8 { + const A = 0b0000_0001u8; + const B = 0b0001_1110u8; + } + } + + impl fmt::Display for MultiBitFmtFlags { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.0, f) + } + } + + impl str::FromStr for MultiBitFmtFlags { + type Err = crate::parser::ParseError; + + fn from_str(s: &str) -> Result { + Ok(MultiBitFmtFlags(s.parse()?)) + } + } + + format_parse_case(FmtFlags::empty()); + format_parse_case(FmtFlags::all()); + format_parse_case(FmtFlags::고양이); + format_parse_case(FmtFlags::고양이 | FmtFlags::개); + format_parse_case(FmtFlags::물고기_고양이); + format_parse_case(FmtFlags::from_bits_retain(0xb8)); + format_parse_case(FmtFlags::from_bits_retain(0x20)); + format_parse_case(MultiBitFmtFlags::from_bits_retain(3)); + + parse_case(FmtFlags::empty(), ""); + parse_case(FmtFlags::empty(), " \r\n\t"); + parse_case(FmtFlags::empty(), "0x0"); + parse_case(FmtFlags::empty(), "0x0"); + + parse_case(FmtFlags::고양이, "고양이"); + parse_case(FmtFlags::고양이, " 고양이 "); + parse_case(FmtFlags::고양이, "고양이 | 고양이 | 고양이"); + parse_case(FmtFlags::고양이, "0x01"); + + parse_case(FmtFlags::고양이 | FmtFlags::개, "고양이 | 개"); + parse_case(FmtFlags::고양이 | FmtFlags::개, "고양이|개"); + parse_case(FmtFlags::고양이 | FmtFlags::개, "\n고양이|개 "); + + parse_case(FmtFlags::고양이 | FmtFlags::물고기, "물고기_고양이"); + } + + #[test] + fn test_from_str_err() { + fn parse_case(pat: &str, flags: &str) { + let err = flags.parse::().unwrap_err().to_string(); + assert!(err.contains(pat), "`{}` not found in error `{}`", pat, err); + } + + parse_case("empty flag", "|"); + parse_case("empty flag", "|||"); + parse_case("empty flag", "고양이 |"); + parse_case("unrecognized named flag", "NOT_A_FLAG"); + parse_case("unrecognized named flag", "고양이 개"); + parse_case("unrecognized named flag", "고양이 | NOT_A_FLAG"); + parse_case("invalid hex flag", "0xhi"); + parse_case("invalid hex flag", "고양이 | 0xhi"); } #[test] fn test_binary() { assert_eq!(format!("{:b}", Flags::ABC), "111"); assert_eq!(format!("{:#b}", Flags::ABC), "0b111"); - let extra = unsafe { Flags::from_bits_unchecked(0b1010000) }; + let extra = Flags::from_bits_retain(0b1010000); assert_eq!(format!("{:b}", Flags::ABC | extra), "1010111"); assert_eq!(format!("{:#b}", Flags::ABC | extra), "0b1010111"); } @@ -1517,7 +1332,7 @@ mod tests { fn test_octal() { assert_eq!(format!("{:o}", LongFlags::LONG_A), "177777"); assert_eq!(format!("{:#o}", LongFlags::LONG_A), "0o177777"); - let extra = unsafe { LongFlags::from_bits_unchecked(0o5000000) }; + let extra = LongFlags::from_bits_retain(0o5000000); assert_eq!(format!("{:o}", LongFlags::LONG_A | extra), "5177777"); assert_eq!(format!("{:#o}", LongFlags::LONG_A | extra), "0o5177777"); } @@ -1526,7 +1341,7 @@ mod tests { fn test_lowerhex() { assert_eq!(format!("{:x}", LongFlags::LONG_A), "ffff"); assert_eq!(format!("{:#x}", LongFlags::LONG_A), "0xffff"); - let extra = unsafe { LongFlags::from_bits_unchecked(0xe00000) }; + let extra = LongFlags::from_bits_retain(0xe00000); assert_eq!(format!("{:x}", LongFlags::LONG_A | extra), "e0ffff"); assert_eq!(format!("{:#x}", LongFlags::LONG_A | extra), "0xe0ffff"); } @@ -1535,17 +1350,19 @@ mod tests { fn test_upperhex() { assert_eq!(format!("{:X}", LongFlags::LONG_A), "FFFF"); assert_eq!(format!("{:#X}", LongFlags::LONG_A), "0xFFFF"); - let extra = unsafe { LongFlags::from_bits_unchecked(0xe00000) }; + let extra = LongFlags::from_bits_retain(0xe00000); assert_eq!(format!("{:X}", LongFlags::LONG_A | extra), "E0FFFF"); assert_eq!(format!("{:#X}", LongFlags::LONG_A | extra), "0xE0FFFF"); } mod submodule { bitflags! { + #[derive(Clone, Copy)] pub struct PublicFlags: i8 { const X = 0; } + #[derive(Clone, Copy)] struct PrivateFlags: i8 { const Y = 0; } @@ -1569,6 +1386,7 @@ mod tests { bitflags! { /// baz + #[derive(Clone, Copy)] struct Flags: foo::Bar { const A = 0b00000001; #[cfg(foo)] @@ -1582,19 +1400,21 @@ mod tests { #[test] fn test_in_function() { bitflags! { - struct Flags: u8 { + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct Flags: u8 { const A = 1; #[cfg(any())] // false const B = 2; } } assert_eq!(Flags::all(), Flags::A); - assert_eq!(format!("{:?}", Flags::A), "A"); + assert_eq!(format!("{:?}", Flags::A), "Flags(A)"); } #[test] fn test_deprecated() { bitflags! { + #[derive(Clone, Copy)] pub struct TestFlags: u32 { #[deprecated(note = "Use something else.")] const ONE = 1; @@ -1606,6 +1426,7 @@ mod tests { fn test_pub_crate() { mod module { bitflags! { + #[derive(Clone, Copy)] pub (crate) struct Test: u8 { const FOO = 1; } @@ -1622,6 +1443,7 @@ mod tests { bitflags! { // `pub (in super)` means only the module `module` will // be able to access this. + #[derive(Clone, Copy)] pub (in super) struct Test: u8 { const FOO = 1; } @@ -1647,6 +1469,7 @@ mod tests { #[test] fn test_zero_value_flags() { bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Flags: u32 { const NONE = 0b0; const SOME = 0b1; @@ -1657,8 +1480,7 @@ mod tests { assert!(Flags::SOME.contains(Flags::NONE)); assert!(Flags::NONE.is_empty()); - assert_eq!(format!("{:?}", Flags::empty()), "NONE"); - assert_eq!(format!("{:?}", Flags::SOME), "SOME"); + assert_eq!(format!("{:?}", Flags::SOME), "Flags(NONE | SOME)"); } #[test] @@ -1669,62 +1491,201 @@ mod tests { #[test] fn test_u128_bitflags() { bitflags! { - struct Flags128: u128 { + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct Flags: u128 { const A = 0x0000_0000_0000_0000_0000_0000_0000_0001; const B = 0x0000_0000_0000_1000_0000_0000_0000_0000; const C = 0x8000_0000_0000_0000_0000_0000_0000_0000; - const ABC = Self::A.bits | Self::B.bits | Self::C.bits; + const ABC = Self::A.bits() | Self::B.bits() | Self::C.bits(); } } - assert_eq!(Flags128::ABC, Flags128::A | Flags128::B | Flags128::C); - assert_eq!(Flags128::A.bits, 0x0000_0000_0000_0000_0000_0000_0000_0001); - assert_eq!(Flags128::B.bits, 0x0000_0000_0000_1000_0000_0000_0000_0000); - assert_eq!(Flags128::C.bits, 0x8000_0000_0000_0000_0000_0000_0000_0000); - assert_eq!( - Flags128::ABC.bits, - 0x8000_0000_0000_1000_0000_0000_0000_0001 - ); - assert_eq!(format!("{:?}", Flags128::A), "A"); - assert_eq!(format!("{:?}", Flags128::B), "B"); - assert_eq!(format!("{:?}", Flags128::C), "C"); - assert_eq!(format!("{:?}", Flags128::ABC), "A | B | C | ABC"); + assert_eq!(Flags::ABC, Flags::A | Flags::B | Flags::C); + assert_eq!(Flags::A.bits(), 0x0000_0000_0000_0000_0000_0000_0000_0001); + assert_eq!(Flags::B.bits(), 0x0000_0000_0000_1000_0000_0000_0000_0000); + assert_eq!(Flags::C.bits(), 0x8000_0000_0000_0000_0000_0000_0000_0000); + assert_eq!(Flags::ABC.bits(), 0x8000_0000_0000_1000_0000_0000_0000_0001); + assert_eq!(format!("{:?}", Flags::A), "Flags(A)"); + assert_eq!(format!("{:?}", Flags::B), "Flags(B)"); + assert_eq!(format!("{:?}", Flags::C), "Flags(C)"); + assert_eq!(format!("{:?}", Flags::ABC), "Flags(A | B | C)"); } #[test] - fn test_serde_bitflags_serialize() { - let flags = SerdeFlags::A | SerdeFlags::B; + fn test_from_bits_edge_cases() { + bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct Flags: u8 { + const A = 0b00000001; + const BC = 0b00000110; + } + } - let serialized = serde_json::to_string(&flags).unwrap(); + let flags = Flags::from_bits(0b00000100); + assert_eq!(flags, None); + let flags = Flags::from_bits(0b00000101); + assert_eq!(flags, None); + } - assert_eq!(serialized, r#"{"bits":3}"#); + #[test] + fn test_from_bits_truncate_edge_cases() { + bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct Flags: u8 { + const A = 0b00000001; + const BC = 0b00000110; + } + } + + let flags = Flags::from_bits_truncate(0b00000100); + assert_eq!(flags, Flags::empty()); + let flags = Flags::from_bits_truncate(0b00000101); + assert_eq!(flags, Flags::A); } #[test] - fn test_serde_bitflags_deserialize() { - let deserialized: SerdeFlags = serde_json::from_str(r#"{"bits":12}"#).unwrap(); + fn test_iter() { + bitflags! { + #[derive(Clone, Copy, Debug, PartialEq, Eq)] + struct Flags: u32 { + const ONE = 0b001; + const TWO = 0b010; + const THREE = 0b100; + #[cfg(windows)] + const FOUR_WIN = 0b1000; + #[cfg(unix)] + const FOUR_UNIX = 0b10000; + const FIVE = 0b01000100; + } + } + + let count = { + #[cfg(any(unix, windows))] + { + 5 + } + + #[cfg(not(any(unix, windows)))] + { + 4 + } + }; + + let flags = Flags::all(); + assert_eq!(flags.into_iter().count(), count); + + for flag in flags.into_iter() { + assert!(flags.contains(flag)); + } - let expected = SerdeFlags::C | SerdeFlags::D; + let mut iter = flags.iter_names(); - assert_eq!(deserialized.bits, expected.bits); + assert_eq!(iter.next().unwrap(), ("ONE", Flags::ONE)); + assert_eq!(iter.next().unwrap(), ("TWO", Flags::TWO)); + assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE)); + + #[cfg(unix)] + { + assert_eq!(iter.next().unwrap(), ("FOUR_UNIX", Flags::FOUR_UNIX)); + } + #[cfg(windows)] + { + assert_eq!(iter.next().unwrap(), ("FOUR_WIN", Flags::FOUR_WIN)); + } + + assert_eq!(iter.next().unwrap(), ("FIVE", Flags::FIVE)); + + assert_eq!(iter.next(), None); + + let flags = Flags::empty(); + assert_eq!(flags.into_iter().count(), 0); + + let flags = Flags::ONE | Flags::THREE; + assert_eq!(flags.into_iter().count(), 2); + + let mut iter = flags.iter_names(); + + assert_eq!(iter.next().unwrap(), ("ONE", Flags::ONE)); + assert_eq!(iter.next().unwrap(), ("THREE", Flags::THREE)); + assert_eq!(iter.next(), None); + + let flags = Flags::from_bits_retain(0b1000_0000); + assert_eq!(flags.into_iter().count(), 1); + assert_eq!(flags.iter_names().count(), 0); + } + + #[test] + fn into_iter_from_iter_roundtrip() { + let flags = Flags::ABC | Flags::from_bits_retain(0b1000_0000); + + assert_eq!(flags, flags.into_iter().collect::()); } #[test] - fn test_serde_bitflags_roundtrip() { - let flags = SerdeFlags::A | SerdeFlags::B; + fn test_from_name() { + let flags = Flags::all(); - let deserialized: SerdeFlags = serde_json::from_str(&serde_json::to_string(&flags).unwrap()).unwrap(); + let mut rebuilt = Flags::empty(); - assert_eq!(deserialized.bits, flags.bits); + for (name, value) in flags.iter_names() { + assert_eq!(value, Flags::from_name(name).unwrap()); + + rebuilt |= Flags::from_name(name).unwrap(); + } + + assert_eq!(flags, rebuilt); } - bitflags! { - #[derive(serde::Serialize, serde::Deserialize)] - struct SerdeFlags: u32 { - const A = 1; - const B = 2; - const C = 4; - const D = 8; + #[test] + fn bits_types() { + bitflags! { + pub struct I8: i8 { + const A = 1; + } + + pub struct I16: i16 { + const A = 1; + } + + pub struct I32: i32 { + const A = 1; + } + + pub struct I64: i64 { + const A = 1; + } + + pub struct I128: i128 { + const A = 1; + } + + pub struct Isize: isize { + const A = 1; + } + + pub struct U8: u8 { + const A = 1; + } + + pub struct U16: u16 { + const A = 1; + } + + pub struct U32: u32 { + const A = 1; + } + + pub struct U64: u64 { + const A = 1; + } + + pub struct U128: u128 { + const A = 1; + } + + pub struct Usize: usize { + const A = 1; + } } } } diff --git a/src/parser.rs b/src/parser.rs new file mode 100644 index 0000000..48f3c61 --- /dev/null +++ b/src/parser.rs @@ -0,0 +1,123 @@ +//! Parsing flags from text. +//! +//! `bitflags` defines the following *whitespace-insensitive*, *case-sensitive* grammar for flags formatted +//! as text: +//! +//! - _Flags:_ (_Flag_)`|`* +//! - _Flag:_ _Identifier_ | _HexNumber_ +//! - _Identifier:_ Any Rust identifier +//! - _HexNumber_: `0x`([0-9a-fA-F])* +//! +//! As an example, this is how `Flags::A | Flags::B | 0x0c` can be represented as text: +//! +//! ```text +//! A | B | 0x0c +//! ``` +//! +//! Alternatively, it could be represented without whitespace: +//! +//! ```text +//! A|B|0x0C +//! ``` +//! +//! Note that identifiers are *case-sensitive*, so the following is *not equivalent*: +//! +//! ```text +//! a | b | 0x0c +//! ``` + +#![allow(clippy::let_unit_value)] + +use core::fmt; + +/// An error encountered while parsing flags from text. +#[derive(Debug)] +pub struct ParseError(ParseErrorKind); + +#[derive(Debug)] +#[allow(clippy::enum_variant_names)] +enum ParseErrorKind { + EmptyFlag, + InvalidNamedFlag { + #[cfg(not(feature = "std"))] + got: (), + #[cfg(feature = "std")] + got: String, + }, + InvalidHexFlag { + #[cfg(not(feature = "std"))] + got: (), + #[cfg(feature = "std")] + got: String, + }, +} + +impl ParseError { + /// An invalid hex flag was encountered. + pub fn invalid_hex_flag(flag: impl fmt::Display) -> Self { + let _flag = flag; + + let got = { + #[cfg(feature = "std")] + { + _flag.to_string() + } + }; + + ParseError(ParseErrorKind::InvalidHexFlag { got }) + } + + /// A named flag that doesn't correspond to any on the flags type was encountered. + pub fn invalid_named_flag(flag: impl fmt::Display) -> Self { + let _flag = flag; + + let got = { + #[cfg(feature = "std")] + { + _flag.to_string() + } + }; + + ParseError(ParseErrorKind::InvalidNamedFlag { got }) + } + + /// A hex or named flag wasn't found between separators. + pub const fn empty_flag() -> Self { + ParseError(ParseErrorKind::EmptyFlag) + } +} + +impl fmt::Display for ParseError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match &self.0 { + ParseErrorKind::InvalidNamedFlag { got } => { + let _got = got; + + write!(f, "unrecognized named flag")?; + + #[cfg(feature = "std")] + { + write!(f, " `{}`", _got)?; + } + } + ParseErrorKind::InvalidHexFlag { got } => { + let _got = got; + + write!(f, "invalid hex flag")?; + + #[cfg(feature = "std")] + { + write!(f, " `{}`", _got)?; + } + } + ParseErrorKind::EmptyFlag => { + write!(f, "encountered empty flag")?; + } + } + + Ok(()) + } +} + +#[cfg(feature = "std")] +impl std::error::Error for ParseError {} diff --git a/src/public.rs b/src/public.rs new file mode 100644 index 0000000..643f843 --- /dev/null +++ b/src/public.rs @@ -0,0 +1,467 @@ +//! Generate the user-facing flags type. +//! +//! The code here belongs to the end-user, so new trait implementations and methods can't be +//! added without potentially breaking users. + +/// Declare the user-facing bitflags struct. +/// +/// This type is guaranteed to be a newtype with a `bitflags`-facing type as its single field. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __declare_public_bitflags { + ( + $(#[$outer:meta])* + $vis:vis struct $BitFlags:ident; + ) => { + $(#[$outer])* + $vis struct $BitFlags(<$BitFlags as $crate::__private::PublicFlags>::Internal); + }; +} + +/// Implement functions on the public (user-facing) bitflags type. +/// +/// We need to be careful about adding new methods and trait implementations here because they +/// could conflict with items added by the end-user. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_public_bitflags { + ( + $PublicBitFlags:ident: $T:ty, $InternalBitFlags:ident, $Iter:ident, $IterNames:ident; + ) => { + impl $crate::__private::core::fmt::Binary for $PublicBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + $crate::__private::core::fmt::Binary::fmt(&self.0, f) + } + } + + impl $crate::__private::core::fmt::Octal for $PublicBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + $crate::__private::core::fmt::Octal::fmt(&self.0, f) + } + } + + impl $crate::__private::core::fmt::LowerHex for $PublicBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + $crate::__private::core::fmt::LowerHex::fmt(&self.0, f) + } + } + + impl $crate::__private::core::fmt::UpperHex for $PublicBitFlags { + fn fmt(&self, f: &mut $crate::__private::core::fmt::Formatter) -> $crate::__private::core::fmt::Result { + $crate::__private::core::fmt::UpperHex::fmt(&self.0, f) + } + } + + impl $PublicBitFlags { + /// Returns an empty set of flags. + #[inline] + pub const fn empty() -> Self { + Self($InternalBitFlags::empty()) + } + + /// Returns the set containing all flags. + #[inline] + pub const fn all() -> Self { + Self($InternalBitFlags::all()) + } + + /// Returns the raw value of the flags currently stored. + #[inline] + pub const fn bits(&self) -> $T { + self.0.bits() + } + + /// Convert from underlying bit representation, unless that + /// representation contains bits that do not correspond to a flag. + #[inline] + pub const fn from_bits(bits: $T) -> $crate::__private::core::option::Option { + match $InternalBitFlags::from_bits(bits) { + $crate::__private::core::option::Option::Some(bits) => $crate::__private::core::option::Option::Some(Self(bits)), + $crate::__private::core::option::Option::None => $crate::__private::core::option::Option::None, + } + } + + /// Convert from underlying bit representation, dropping any bits + /// that do not correspond to flags. + #[inline] + pub const fn from_bits_truncate(bits: $T) -> Self { + Self($InternalBitFlags::from_bits_truncate(bits)) + } + + /// Convert from underlying bit representation, preserving all + /// bits (even those not corresponding to a defined flag). + #[inline] + pub const fn from_bits_retain(bits: $T) -> Self { + Self($InternalBitFlags::from_bits_retain(bits)) + } + + /// Get the value for a flag from its stringified name. + /// + /// Names are _case-sensitive_, so must correspond exactly to + /// the identifier given to the flag. + #[inline] + pub fn from_name(name: &str) -> $crate::__private::core::option::Option { + match $InternalBitFlags::from_name(name) { + $crate::__private::core::option::Option::Some(bits) => $crate::__private::core::option::Option::Some(Self(bits)), + $crate::__private::core::option::Option::None => $crate::__private::core::option::Option::None, + } + } + + /// Iterate over enabled flag values. + #[inline] + pub const fn iter(&self) -> $Iter { + self.0.iter() + } + + /// Iterate over enabled flag values with their stringified names. + #[inline] + pub const fn iter_names(&self) -> $IterNames { + self.0.iter_names() + } + + /// Returns `true` if no flags are currently stored. + #[inline] + pub const fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// Returns `true` if all flags are currently set. + #[inline] + pub const fn is_all(&self) -> bool { + self.0.is_all() + } + + /// Returns `true` if there are flags common to both `self` and `other`. + #[inline] + pub const fn intersects(&self, other: Self) -> bool { + self.0.intersects(other.0) + } + + /// Returns `true` if all of the flags in `other` are contained within `self`. + #[inline] + pub const fn contains(&self, other: Self) -> bool { + self.0.contains(other.0) + } + + /// Inserts the specified flags in-place. + #[inline] + pub fn insert(&mut self, other: Self) { + self.0.insert(other.0) + } + + /// Removes the specified flags in-place. + #[inline] + pub fn remove(&mut self, other: Self) { + self.0.remove(other.0) + } + + /// Toggles the specified flags in-place. + #[inline] + pub fn toggle(&mut self, other: Self) { + self.0.toggle(other.0) + } + + /// Inserts or removes the specified flags depending on the passed value. + #[inline] + pub fn set(&mut self, other: Self, value: bool) { + self.0.set(other.0, value) + } + + /// Returns the intersection between the flags in `self` and + /// `other`. + /// + /// Specifically, the returned set contains only the flags which are + /// present in *both* `self` *and* `other`. + /// + /// This is equivalent to using the `&` operator (e.g. + /// [`ops::BitAnd`]), as in `flags & other`. + /// + /// [`ops::BitAnd`]: https://doc.rust-lang.org/std/ops/trait.BitAnd.html + #[inline] + #[must_use] + pub const fn intersection(self, other: Self) -> Self { + Self(self.0.intersection(other.0)) + } + + /// Returns the union of between the flags in `self` and `other`. + /// + /// Specifically, the returned set contains all flags which are + /// present in *either* `self` *or* `other`, including any which are + /// present in both (see [`Self::symmetric_difference`] if that + /// is undesirable). + /// + /// This is equivalent to using the `|` operator (e.g. + /// [`ops::BitOr`]), as in `flags | other`. + /// + /// [`ops::BitOr`]: https://doc.rust-lang.org/std/ops/trait.BitOr.html + #[inline] + #[must_use] + pub const fn union(self, other: Self) -> Self { + Self(self.0.union(other.0)) + } + + /// Returns the difference between the flags in `self` and `other`. + /// + /// Specifically, the returned set contains all flags present in + /// `self`, except for the ones present in `other`. + /// + /// It is also conceptually equivalent to the "bit-clear" operation: + /// `flags & !other` (and this syntax is also supported). + /// + /// This is equivalent to using the `-` operator (e.g. + /// [`ops::Sub`]), as in `flags - other`. + /// + /// [`ops::Sub`]: https://doc.rust-lang.org/std/ops/trait.Sub.html + #[inline] + #[must_use] + pub const fn difference(self, other: Self) -> Self { + Self(self.0.difference(other.0)) + } + + /// Returns the [symmetric difference][sym-diff] between the flags + /// in `self` and `other`. + /// + /// Specifically, the returned set contains the flags present which + /// are present in `self` or `other`, but that are not present in + /// both. Equivalently, it contains the flags present in *exactly + /// one* of the sets `self` and `other`. + /// + /// This is equivalent to using the `^` operator (e.g. + /// [`ops::BitXor`]), as in `flags ^ other`. + /// + /// [sym-diff]: https://en.wikipedia.org/wiki/Symmetric_difference + /// [`ops::BitXor`]: https://doc.rust-lang.org/std/ops/trait.BitXor.html + #[inline] + #[must_use] + pub const fn symmetric_difference(self, other: Self) -> Self { + Self(self.0.symmetric_difference(other.0)) + } + + /// Returns the complement of this set of flags. + /// + /// Specifically, the returned set contains all the flags which are + /// not set in `self`, but which are allowed for this type. + /// + /// Alternatively, it can be thought of as the set difference + /// between [`Self::all()`] and `self` (e.g. `Self::all() - self`) + /// + /// This is equivalent to using the `!` operator (e.g. + /// [`ops::Not`]), as in `!flags`. + /// + /// [`Self::all()`]: Self::all + /// [`ops::Not`]: https://doc.rust-lang.org/std/ops/trait.Not.html + #[inline] + #[must_use] + pub const fn complement(self) -> Self { + Self(self.0.complement()) + } + } + + impl $crate::__private::core::ops::BitOr for $PublicBitFlags { + type Output = Self; + + /// Returns the union of the two sets of flags. + #[inline] + fn bitor(self, other: $PublicBitFlags) -> Self { + self.union(other) + } + } + + impl $crate::__private::core::ops::BitOrAssign for $PublicBitFlags { + /// Adds the set of flags. + #[inline] + fn bitor_assign(&mut self, other: Self) { + self.0 = self.0.union(other.0); + } + } + + impl $crate::__private::core::ops::BitXor for $PublicBitFlags { + type Output = Self; + + /// Returns the left flags, but with all the right flags toggled. + #[inline] + fn bitxor(self, other: Self) -> Self { + self.symmetric_difference(other) + } + } + + impl $crate::__private::core::ops::BitXorAssign for $PublicBitFlags { + /// Toggles the set of flags. + #[inline] + fn bitxor_assign(&mut self, other: Self) { + self.0 = self.0.symmetric_difference(other.0); + } + } + + impl $crate::__private::core::ops::BitAnd for $PublicBitFlags { + type Output = Self; + + /// Returns the intersection between the two sets of flags. + #[inline] + fn bitand(self, other: Self) -> Self { + self.intersection(other) + } + } + + impl $crate::__private::core::ops::BitAndAssign for $PublicBitFlags { + /// Disables all flags disabled in the set. + #[inline] + fn bitand_assign(&mut self, other: Self) { + self.0 = self.0.intersection(other.0); + } + } + + impl $crate::__private::core::ops::Sub for $PublicBitFlags { + type Output = Self; + + /// Returns the set difference of the two sets of flags. + #[inline] + fn sub(self, other: Self) -> Self { + self.difference(other) + } + } + + impl $crate::__private::core::ops::SubAssign for $PublicBitFlags { + /// Disables all flags enabled in the set. + #[inline] + fn sub_assign(&mut self, other: Self) { + self.0 = self.0.difference(other.0); + } + } + + impl $crate::__private::core::ops::Not for $PublicBitFlags { + type Output = Self; + + /// Returns the complement of this set of flags. + #[inline] + fn not(self) -> Self { + self.complement() + } + } + + impl $crate::__private::core::iter::Extend<$PublicBitFlags> for $PublicBitFlags { + fn extend>(&mut self, iterator: T) { + for item in iterator { + self.insert(item) + } + } + } + + impl $crate::__private::core::iter::FromIterator<$PublicBitFlags> for $PublicBitFlags { + fn from_iter>(iterator: T) -> Self { + use $crate::__private::core::iter::Extend; + + let mut result = Self::empty(); + result.extend(iterator); + result + } + } + + impl $crate::__private::core::iter::IntoIterator for $PublicBitFlags { + type Item = Self; + type IntoIter = $Iter; + + fn into_iter(self) -> Self::IntoIter { + self.0.iter() + } + } + + impl $crate::BitFlags for $PublicBitFlags { + type Bits = $T; + + type Iter = $Iter; + type IterNames = $IterNames; + + fn empty() -> Self { + $PublicBitFlags::empty() + } + + fn all() -> Self { + $PublicBitFlags::all() + } + + fn bits(&self) -> $T { + $PublicBitFlags::bits(self) + } + + fn from_bits(bits: $T) -> $crate::__private::core::option::Option<$PublicBitFlags> { + $PublicBitFlags::from_bits(bits) + } + + fn from_bits_truncate(bits: $T) -> $PublicBitFlags { + $PublicBitFlags::from_bits_truncate(bits) + } + + fn from_bits_retain(bits: $T) -> $PublicBitFlags { + $PublicBitFlags::from_bits_retain(bits) + } + + fn from_name(name: &str) -> $crate::__private::core::option::Option<$PublicBitFlags> { + $PublicBitFlags::from_name(name) + } + + fn iter(&self) -> Self::Iter { + $PublicBitFlags::iter(self) + } + + fn iter_names(&self) -> Self::IterNames { + $PublicBitFlags::iter_names(self) + } + + fn is_empty(&self) -> bool { + $PublicBitFlags::is_empty(self) + } + + fn is_all(&self) -> bool { + $PublicBitFlags::is_all(self) + } + + fn intersects(&self, other: $PublicBitFlags) -> bool { + $PublicBitFlags::intersects(self, other) + } + + fn contains(&self, other: $PublicBitFlags) -> bool { + $PublicBitFlags::contains(self, other) + } + + fn insert(&mut self, other: $PublicBitFlags) { + $PublicBitFlags::insert(self, other) + } + + fn remove(&mut self, other: $PublicBitFlags) { + $PublicBitFlags::remove(self, other) + } + + fn toggle(&mut self, other: $PublicBitFlags) { + $PublicBitFlags::toggle(self, other) + } + + fn set(&mut self, other: $PublicBitFlags, value: bool) { + $PublicBitFlags::set(self, other, value) + } + } + + impl $crate::__private::ImplementedByBitFlagsMacro for $PublicBitFlags {} + }; +} + +/// Implement constants on the public (user-facing) bitflags type. +#[macro_export(local_inner_macros)] +#[doc(hidden)] +macro_rules! __impl_public_bitflags_consts { + ( + $PublicBitFlags:ident { + $( + $(#[$attr:ident $($args:tt)*])* + $Flag:ident = $value:expr; + )* + } + ) => { + impl $PublicBitFlags { + $( + $(#[$attr $($args)*])* + pub const $Flag: Self = Self::from_bits_retain($value); + )* + } + }; +} diff --git a/src/traits.rs b/src/traits.rs new file mode 100644 index 0000000..85503e6 --- /dev/null +++ b/src/traits.rs @@ -0,0 +1,157 @@ +use core::ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not}; + +/// A trait that is automatically implemented for all bitflags. +/// +/// It should not be implemented manually. +pub trait BitFlags: ImplementedByBitFlagsMacro { + /// The underlying integer type. + type Bits: Bits; + + /// An iterator over enabled flags in an instance of the type. + type Iter: Iterator; + + /// An iterator over the raw names and bits for enabled flags in an instance of the type. + type IterNames: Iterator; + + /// Returns an empty set of flags. + fn empty() -> Self; + + /// Returns the set containing all flags. + fn all() -> Self; + + /// Returns the raw value of the flags currently stored. + fn bits(&self) -> Self::Bits; + + /// Convert from underlying bit representation, unless that + /// representation contains bits that do not correspond to a flag. + /// + /// Note that each [multi-bit flag] is treated as a unit for this comparison. + /// + /// [multi-bit flag]: index.html#multi-bit-flags + fn from_bits(bits: Self::Bits) -> Option + where + Self: Sized; + + /// Convert from underlying bit representation, dropping any bits + /// that do not correspond to flags. + /// + /// Note that each [multi-bit flag] is treated as a unit for this comparison. + /// + /// [multi-bit flag]: index.html#multi-bit-flags + fn from_bits_truncate(bits: Self::Bits) -> Self; + + /// Convert from underlying bit representation, preserving all + /// bits (even those not corresponding to a defined flag). + fn from_bits_retain(bits: Self::Bits) -> Self; + + /// Get the flag for a particular name. + fn from_name(name: &str) -> Option + where + Self: Sized; + + /// Iterate over enabled flag values. + fn iter(&self) -> Self::Iter; + + /// Iterate over the raw names and bits for enabled flag values. + fn iter_names(&self) -> Self::IterNames; + + /// Returns `true` if no flags are currently stored. + fn is_empty(&self) -> bool; + + /// Returns `true` if all flags are currently set. + fn is_all(&self) -> bool; + + /// Returns `true` if there are flags common to both `self` and `other`. + fn intersects(&self, other: Self) -> bool; + + /// Returns `true` if all of the flags in `other` are contained within `self`. + fn contains(&self, other: Self) -> bool; + + /// Inserts the specified flags in-place. + fn insert(&mut self, other: Self); + + /// Removes the specified flags in-place. + fn remove(&mut self, other: Self); + + /// Toggles the specified flags in-place. + fn toggle(&mut self, other: Self); + + /// Inserts or removes the specified flags depending on the passed value. + fn set(&mut self, other: Self, value: bool); +} + +/// A marker trait that signals that an implementation of `BitFlags` came from the `bitflags!` macro. +/// +/// There's nothing stopping an end-user from implementing this trait, but we don't guarantee their +/// manual implementations won't break between non-breaking releases. +#[doc(hidden)] +pub trait ImplementedByBitFlagsMacro {} + +// Not re-exported +pub trait Sealed {} + +// Private implementation details +// +// The `Bits`, `PublicFlags`, and `InternalFlags` traits are implementation details of the `bitflags!` +// macro that we're free to change here. They work with the `bitflags!` macro to separate the generated +// code that belongs to end-users, and the generated code that belongs to this library. + +/// A private trait that encodes the requirements of underlying bits types that can hold flags. +/// +/// This trait may be made public at some future point, but it presents a compatibility hazard +/// so is left internal for now. +#[doc(hidden)] +pub trait Bits: + Clone + + Copy + + BitAnd + + BitAndAssign + + BitOr + + BitOrAssign + + BitXor + + BitXorAssign + + Not + + Sized + + Sealed +{ + /// The value of `Self` where no bits are set. + const EMPTY: Self; + + /// The value of `Self` where all bits are set. + const ALL: Self; +} + +macro_rules! impl_bits { + ($($u:ty, $i:ty,)*) => { + $( + impl Bits for $u { + const EMPTY: $u = 0; + const ALL: $u = <$u>::MAX; + } + + impl Bits for $i { + const EMPTY: $i = 0; + const ALL: $i = <$u>::MAX as $i; + } + + impl Sealed for $u {} + impl Sealed for $i {} + )* + } +} + +impl_bits! { + u8, i8, + u16, i16, + u32, i32, + u64, i64, + u128, i128, + usize, isize, +} + +/// A trait for referencing the `bitflags`-owned internal type +/// without exposing it publicly. +pub trait PublicFlags { + /// The type of the internal field on the generated flags type. + type Internal; +} -- cgit v1.2.3