Snap for 11914274 from 303873469e475b87b5c155fc210da4d5db92991d to 24Q3-release
Change-Id: Iaade1dd523dadae02eeb5a7c0ebcdf913481fa52
diff --git a/.cargo_vcs_info.json b/.cargo_vcs_info.json
index 49de48e..e24ee9b 100644
--- a/.cargo_vcs_info.json
+++ b/.cargo_vcs_info.json
@@ -1,6 +1,6 @@
{
"git": {
- "sha1": "a5f9ce20e9d18444aa9b20c8fea9c00155cbafa3"
+ "sha1": "e5ff0ca84b6aa5c9989c924ebe02527959bb7d02"
},
"path_in_vcs": ""
}
\ No newline at end of file
diff --git a/Android.bp b/Android.bp
index 365685f..20ce3a5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -44,7 +44,7 @@
host_supported: true,
crate_name: "bitflags",
cargo_env_compat: true,
- cargo_pkg_version: "2.4.2",
+ cargo_pkg_version: "2.5.0",
crate_root: "src/lib.rs",
edition: "2021",
apex_available: [
diff --git a/CHANGELOG.md b/CHANGELOG.md
index fd435d2..5d410fc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,14 @@
+# 2.5.0
+
+## What's Changed
+* Derive `Debug` for `Flag<B>` by @tgross35 in https://github.com/bitflags/bitflags/pull/398
+* Support truncating or strict-named variants of parsing and formatting by @KodrAus in https://github.com/bitflags/bitflags/pull/400
+
+## New Contributors
+* @tgross35 made their first contribution in https://github.com/bitflags/bitflags/pull/398
+
+**Full Changelog**: https://github.com/bitflags/bitflags/compare/2.4.2...2.5.0
+
# 2.4.2
## What's Changed
diff --git a/Cargo.toml b/Cargo.toml
index 43595a5..b274599 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -13,7 +13,7 @@
edition = "2021"
rust-version = "1.56.0"
name = "bitflags"
-version = "2.4.2"
+version = "2.5.0"
authors = ["The Rust Project Developers"]
exclude = [
"/tests",
diff --git a/Cargo.toml.orig b/Cargo.toml.orig
index 764bfdc..edc4f02 100644
--- a/Cargo.toml.orig
+++ b/Cargo.toml.orig
@@ -1,7 +1,7 @@
[package]
name = "bitflags"
# NB: When modifying, also modify the number in readme (for breaking changes)
-version = "2.4.2"
+version = "2.5.0"
edition = "2021"
rust-version = "1.56.0"
authors = ["The Rust Project Developers"]
diff --git a/METADATA b/METADATA
index 2863dcb..77080ae 100644
--- a/METADATA
+++ b/METADATA
@@ -8,13 +8,13 @@
license_type: NOTICE
last_upgrade_date {
year: 2024
- month: 2
- day: 21
+ month: 5
+ day: 31
}
homepage: "https://crates.io/crates/bitflags"
identifier {
type: "Archive"
- value: "https://static.crates.io/crates/bitflags/bitflags-2.4.2.crate"
- version: "2.4.2"
+ value: "https://static.crates.io/crates/bitflags/bitflags-2.5.0.crate"
+ version: "2.5.0"
}
}
diff --git a/README.md b/README.md
index a560bc8..652a880 100644
--- a/README.md
+++ b/README.md
@@ -28,7 +28,7 @@
```toml
[dependencies]
-bitflags = "2.4.2"
+bitflags = "2.5.0"
```
and this to your source code:
diff --git a/patches/rules.mk.diff b/patches/rules.mk.diff
index 05c3bef..47616d9 100644
--- a/patches/rules.mk.diff
+++ b/patches/rules.mk.diff
@@ -2,12 +2,13 @@
index ccb9711..8005071 100644
--- b/rules.mk
+++ a/rules.mk
-@@ -9,8 +9,6 @@ MODULE_SRCS := \
-
+@@ -8,4 +8,9 @@ MODULE_SRCS := \
+ $(LOCAL_DIR)/src/lib.rs \
+
MODULE_RUST_EDITION := 2021
- MODULE_LIBRARY_DEPS := \
-- external/rust/crates/arbitrary \
-- external/rust/crates/bytemuck \
- trusty/user/base/lib/libcompiler_builtins-rust \
- trusty/user/base/lib/libcore-rust \
- external/rust/crates/serde \
++MODULE_LIBRARY_DEPS := \
++ trusty/user/base/lib/libcompiler_builtins-rust \
++ trusty/user/base/lib/libcore-rust \
++ external/rust/crates/serde \
++
+ include make/library.mk
diff --git a/src/lib.rs b/src/lib.rs
index 18270f7..606b583 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -17,7 +17,7 @@
```toml
[dependencies.bitflags]
-version = "2.4.2"
+version = "2.5.0"
```
## Generating flags types
@@ -253,7 +253,8 @@
#[doc(hidden)]
pub mod __private {
- #[allow(unused_imports)] // Easier than conditionally checking any optional external dependencies
+ #[allow(unused_imports)]
+ // Easier than conditionally checking any optional external dependencies
pub use crate::{external::__private::*, traits::__private::*};
pub use core;
diff --git a/src/parser.rs b/src/parser.rs
index 130dc2e..34b432d 100644
--- a/src/parser.rs
+++ b/src/parser.rs
@@ -77,8 +77,10 @@
fmt::Result::Ok(())
}
+#[cfg(feature = "serde")]
pub(crate) struct AsDisplay<'a, B>(pub(crate) &'a B);
+#[cfg(feature = "serde")]
impl<'a, B: Flags> fmt::Display for AsDisplay<'a, B>
where
B::Bits: WriteHex,
@@ -135,6 +137,89 @@
}
/**
+Write a flags value as text, ignoring any unknown bits.
+*/
+pub fn to_writer_truncate<B: Flags>(flags: &B, writer: impl Write) -> Result<(), fmt::Error>
+where
+ B::Bits: WriteHex,
+{
+ to_writer(&B::from_bits_truncate(flags.bits()), writer)
+}
+
+/**
+Parse a flags value from text.
+
+This function will fail on any names that don't correspond to defined flags.
+Unknown bits will be ignored.
+*/
+pub fn from_str_truncate<B: Flags>(input: &str) -> Result<B, ParseError>
+where
+ B::Bits: ParseHex,
+{
+ Ok(B::from_bits_truncate(from_str::<B>(input)?.bits()))
+}
+
+/**
+Write only the contained, defined, named flags in a flags value as text.
+*/
+pub fn to_writer_strict<B: Flags>(flags: &B, mut writer: impl Write) -> Result<(), fmt::Error> {
+ // This is a simplified version of `to_writer` that ignores
+ // any bits not corresponding to a named flag
+
+ let mut first = true;
+ let mut iter = flags.iter_names();
+ for (name, _) in &mut iter {
+ if !first {
+ writer.write_str(" | ")?;
+ }
+
+ first = false;
+ writer.write_str(name)?;
+ }
+
+ fmt::Result::Ok(())
+}
+
+/**
+Parse a flags value from text.
+
+This function will fail on any names that don't correspond to defined flags.
+This function will fail to parse hex values.
+*/
+pub fn from_str_strict<B: Flags>(input: &str) -> Result<B, ParseError> {
+ // This is a simplified version of `from_str` that ignores
+ // any bits not corresponding to a named flag
+
+ let mut parsed_flags = B::empty();
+
+ // If the input is empty then return an empty set of flags
+ if input.trim().is_empty() {
+ return Ok(parsed_flags);
+ }
+
+ for flag in input.split('|') {
+ let flag = flag.trim();
+
+ // If the flag is empty then we've got missing input
+ if flag.is_empty() {
+ return Err(ParseError::empty_flag());
+ }
+
+ // If the flag starts with `0x` then it's a hex number
+ // These aren't supported in the strict parser
+ if flag.starts_with("0x") {
+ return Err(ParseError::invalid_hex_flag("unsupported hex flag value"));
+ }
+
+ let parsed_flag = B::from_name(flag).ok_or_else(|| ParseError::invalid_named_flag(flag))?;
+
+ parsed_flags.insert(parsed_flag);
+ }
+
+ Ok(parsed_flags)
+}
+
+/**
Encode a value as a hex string.
Implementors of this trait should not write the `0x` prefix.
diff --git a/src/tests/parser.rs b/src/tests/parser.rs
index b370785..fb27225 100644
--- a/src/tests/parser.rs
+++ b/src/tests/parser.rs
@@ -1,9 +1,6 @@
use super::*;
-use crate::{
- parser::{from_str, to_writer},
- Flags,
-};
+use crate::{parser::*, Flags};
#[test]
#[cfg(not(miri))] // Very slow in miri
@@ -22,6 +19,51 @@
}
}
+#[test]
+#[cfg(not(miri))] // Very slow in miri
+fn roundtrip_truncate() {
+ let mut s = String::new();
+
+ for a in 0u8..=255 {
+ for b in 0u8..=255 {
+ let f = TestFlags::from_bits_retain(a | b);
+
+ s.clear();
+ to_writer_truncate(&f, &mut s).unwrap();
+
+ assert_eq!(
+ TestFlags::from_bits_truncate(f.bits()),
+ from_str_truncate::<TestFlags>(&s).unwrap()
+ );
+ }
+ }
+}
+
+#[test]
+#[cfg(not(miri))] // Very slow in miri
+fn roundtrip_strict() {
+ let mut s = String::new();
+
+ for a in 0u8..=255 {
+ for b in 0u8..=255 {
+ let f = TestFlags::from_bits_retain(a | b);
+
+ s.clear();
+ to_writer_strict(&f, &mut s).unwrap();
+
+ let mut strict = TestFlags::empty();
+ for (_, flag) in f.iter_names() {
+ strict |= flag;
+ }
+ let f = strict;
+
+ if let Ok(s) = from_str_strict::<TestFlags>(&s) {
+ assert_eq!(f, s);
+ }
+ }
+ }
+}
+
mod from_str {
use super::*;
@@ -97,6 +139,8 @@
assert_eq!("ABC", write(TestFlagsInvert::all()));
+ assert_eq!("0x1", write(TestOverlapping::from_bits_retain(1)));
+
assert_eq!("A", write(TestOverlappingFull::C));
assert_eq!(
"A | D",
@@ -114,3 +158,175 @@
s
}
}
+
+mod from_str_truncate {
+ use super::*;
+
+ #[test]
+ fn valid() {
+ assert_eq!(0, from_str_truncate::<TestFlags>("").unwrap().bits());
+
+ assert_eq!(1, from_str_truncate::<TestFlags>("A").unwrap().bits());
+ assert_eq!(1, from_str_truncate::<TestFlags>(" A ").unwrap().bits());
+ assert_eq!(
+ 1 | 1 << 1 | 1 << 2,
+ from_str_truncate::<TestFlags>("A | B | C").unwrap().bits()
+ );
+ assert_eq!(
+ 1 | 1 << 1 | 1 << 2,
+ from_str_truncate::<TestFlags>("A\n|\tB\r\n| C ")
+ .unwrap()
+ .bits()
+ );
+ assert_eq!(
+ 1 | 1 << 1 | 1 << 2,
+ from_str_truncate::<TestFlags>("A|B|C").unwrap().bits()
+ );
+
+ assert_eq!(0, from_str_truncate::<TestFlags>("0x8").unwrap().bits());
+ assert_eq!(1, from_str_truncate::<TestFlags>("A | 0x8").unwrap().bits());
+ assert_eq!(
+ 1 | 1 << 1,
+ from_str_truncate::<TestFlags>("0x1 | 0x8 | B")
+ .unwrap()
+ .bits()
+ );
+
+ assert_eq!(
+ 1 | 1 << 1,
+ from_str_truncate::<TestUnicode>("一 | 二").unwrap().bits()
+ );
+ }
+}
+
+mod to_writer_truncate {
+ use super::*;
+
+ #[test]
+ fn cases() {
+ assert_eq!("", write(TestFlags::empty()));
+ assert_eq!("A", write(TestFlags::A));
+ assert_eq!("A | B | C", write(TestFlags::all()));
+ assert_eq!("", write(TestFlags::from_bits_retain(1 << 3)));
+ assert_eq!(
+ "A",
+ write(TestFlags::A | TestFlags::from_bits_retain(1 << 3))
+ );
+
+ assert_eq!("", write(TestZero::ZERO));
+
+ assert_eq!("ABC", write(TestFlagsInvert::all()));
+
+ assert_eq!("0x1", write(TestOverlapping::from_bits_retain(1)));
+
+ assert_eq!("A", write(TestOverlappingFull::C));
+ assert_eq!(
+ "A | D",
+ write(TestOverlappingFull::C | TestOverlappingFull::D)
+ );
+ }
+
+ fn write<F: Flags>(value: F) -> String
+ where
+ F::Bits: crate::parser::WriteHex,
+ {
+ let mut s = String::new();
+
+ to_writer_truncate(&value, &mut s).unwrap();
+ s
+ }
+}
+
+mod from_str_strict {
+ use super::*;
+
+ #[test]
+ fn valid() {
+ assert_eq!(0, from_str_strict::<TestFlags>("").unwrap().bits());
+
+ assert_eq!(1, from_str_strict::<TestFlags>("A").unwrap().bits());
+ assert_eq!(1, from_str_strict::<TestFlags>(" A ").unwrap().bits());
+ assert_eq!(
+ 1 | 1 << 1 | 1 << 2,
+ from_str_strict::<TestFlags>("A | B | C").unwrap().bits()
+ );
+ assert_eq!(
+ 1 | 1 << 1 | 1 << 2,
+ from_str_strict::<TestFlags>("A\n|\tB\r\n| C ")
+ .unwrap()
+ .bits()
+ );
+ assert_eq!(
+ 1 | 1 << 1 | 1 << 2,
+ from_str_strict::<TestFlags>("A|B|C").unwrap().bits()
+ );
+
+ assert_eq!(
+ 1 | 1 << 1,
+ from_str_strict::<TestUnicode>("一 | 二").unwrap().bits()
+ );
+ }
+
+ #[test]
+ fn invalid() {
+ assert!(from_str_strict::<TestFlags>("a")
+ .unwrap_err()
+ .to_string()
+ .starts_with("unrecognized named flag"));
+ assert!(from_str_strict::<TestFlags>("A & B")
+ .unwrap_err()
+ .to_string()
+ .starts_with("unrecognized named flag"));
+
+ assert!(from_str_strict::<TestFlags>("0x1")
+ .unwrap_err()
+ .to_string()
+ .starts_with("invalid hex flag"));
+ assert!(from_str_strict::<TestFlags>("0xg")
+ .unwrap_err()
+ .to_string()
+ .starts_with("invalid hex flag"));
+ assert!(from_str_strict::<TestFlags>("0xffffffffffff")
+ .unwrap_err()
+ .to_string()
+ .starts_with("invalid hex flag"));
+ }
+}
+
+mod to_writer_strict {
+ use super::*;
+
+ #[test]
+ fn cases() {
+ assert_eq!("", write(TestFlags::empty()));
+ assert_eq!("A", write(TestFlags::A));
+ assert_eq!("A | B | C", write(TestFlags::all()));
+ assert_eq!("", write(TestFlags::from_bits_retain(1 << 3)));
+ assert_eq!(
+ "A",
+ write(TestFlags::A | TestFlags::from_bits_retain(1 << 3))
+ );
+
+ assert_eq!("", write(TestZero::ZERO));
+
+ assert_eq!("ABC", write(TestFlagsInvert::all()));
+
+ assert_eq!("", write(TestOverlapping::from_bits_retain(1)));
+
+ assert_eq!("A", write(TestOverlappingFull::C));
+ assert_eq!(
+ "A | D",
+ write(TestOverlappingFull::C | TestOverlappingFull::D)
+ );
+ }
+
+ fn write<F: Flags>(value: F) -> String
+ where
+ F::Bits: crate::parser::WriteHex,
+ {
+ let mut s = String::new();
+
+ to_writer_strict(&value, &mut s).unwrap();
+ s
+ }
+}
diff --git a/src/traits.rs b/src/traits.rs
index 2823514..3905d7d 100644
--- a/src/traits.rs
+++ b/src/traits.rs
@@ -11,6 +11,7 @@
/**
A defined flags value that may be named or unnamed.
*/
+#[derive(Debug)]
pub struct Flag<B> {
name: &'static str,
value: B,