mirror of
https://gitee.com/openharmony/third_party_rust_bitflags
synced 2024-11-27 01:11:37 +00:00
Add support for "unknown" bits.
This allows bitflags to be robustly used in cases where bit flags are defined outside the program and are subject to extension after the program has been compiled. In such cases, the new function `from_bits_unknown()` can create a bitflags structure where some of the stored bits have no pre-defined meaning to the program; nevertheless, the program can store and manipulate them successfully rather than mis-behaving.
This commit is contained in:
parent
de303080cf
commit
8b9676ed35
107
src/lib.rs
107
src/lib.rs
@ -146,14 +146,21 @@
|
||||
//! The following methods are defined for the generated `struct`:
|
||||
//!
|
||||
//! - `empty`: an empty set of flags
|
||||
//! - `all`: the set of all flags
|
||||
//! - `bits`: the raw value of the flags currently stored
|
||||
//! - `all`: the set of all known flags
|
||||
//! - `bits`: the raw value of the flags currently stored (includes both known
|
||||
//! and unknown bits)
|
||||
//! - `known_bits`: the raw value of the flags currently stored with any
|
||||
//! unknown bits masked out
|
||||
//! - `unknown_bits`: the raw value of the flags currently stored with any
|
||||
//! known bits masked out
|
||||
//! - `from_bits`: convert from underlying bit representation, unless that
|
||||
//! representation contains bits that do not correspond to a flag
|
||||
//! - `from_bits_truncate`: convert from underlying bit representation, dropping
|
||||
//! any bits that do not correspond to flags
|
||||
//! - `from_bits_unknown`: convert from underlying bit representation, keeping
|
||||
//! all bits (even those not corresponding to flags)
|
||||
//! - `is_empty`: `true` if no flags are currently stored
|
||||
//! - `is_all`: `true` if all flags are currently set
|
||||
//! - `is_all`: `true` if all flags are currently set (with no unknown flags)
|
||||
//! - `intersects`: `true` if there are flags common to both `self` and `other`
|
||||
//! - `contains`: `true` all of the flags in `other` are contained within `self`
|
||||
//! - `insert`: inserts the specified flags in-place
|
||||
@ -513,6 +520,14 @@ macro_rules! __impl_bitflags {
|
||||
f.write_str(__bitflags_stringify!($Flag))?;
|
||||
}
|
||||
)+
|
||||
if self.unknown_bits() != 0 {
|
||||
if !first {
|
||||
f.write_str(" | ")?;
|
||||
}
|
||||
first = false;
|
||||
f.write_str("0x")?;
|
||||
$crate::_core::fmt::LowerHex::fmt(&self.unknown_bits(), f)?;
|
||||
}
|
||||
if first {
|
||||
f.write_str("(empty)")?;
|
||||
}
|
||||
@ -589,6 +604,22 @@ macro_rules! __impl_bitflags {
|
||||
}
|
||||
}
|
||||
|
||||
__fn_bitflags! {
|
||||
/// Returns the raw value of any "known" flags currently stored.
|
||||
#[inline]
|
||||
pub const fn known_bits(&self) -> $T {
|
||||
self.bits & $BitFlags::all().bits()
|
||||
}
|
||||
}
|
||||
|
||||
__fn_bitflags! {
|
||||
/// Returns the raw value of any "unknown" flags currently stored.
|
||||
#[inline]
|
||||
pub const fn unknown_bits(&self) -> $T {
|
||||
self.bits & !$BitFlags::all().bits()
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert from underlying bit representation, unless that
|
||||
/// representation contains bits that do not correspond to a flag.
|
||||
#[inline]
|
||||
@ -609,6 +640,15 @@ macro_rules! __impl_bitflags {
|
||||
}
|
||||
}
|
||||
|
||||
__fn_bitflags! {
|
||||
/// Convert from underlying bit representation, allowing
|
||||
/// "unknown" bits that do not correspond to a flag.
|
||||
#[inline]
|
||||
pub const fn from_bits_unknown(bits: $T) -> $BitFlags {
|
||||
$BitFlags { bits }
|
||||
}
|
||||
}
|
||||
|
||||
__fn_bitflags! {
|
||||
/// Returns `true` if no flags are currently stored.
|
||||
#[inline]
|
||||
@ -979,6 +1019,35 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_from_bits_unknown() {
|
||||
let u = Flags::from_bits_unknown(0b1000);
|
||||
assert_eq!(Flags::from_bits_unknown(0), Flags::empty());
|
||||
assert_eq!(Flags::from_bits_unknown(0b1), Flags::A);
|
||||
assert_eq!(Flags::from_bits_unknown(0b10), Flags::B);
|
||||
assert_eq!(Flags::from_bits_unknown(0b11), (Flags::A | Flags::B));
|
||||
assert_eq!(Flags::from_bits_unknown(0b1000), (u | Flags::empty()));
|
||||
assert_eq!(Flags::from_bits_unknown(0b1001), (u | Flags::A));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_known_unknown_bits() {
|
||||
let known = Flags::ABC;
|
||||
let known_bits = known.bits();
|
||||
assert_eq!(known_bits, 0b111);
|
||||
|
||||
let unknown = Flags::from_bits_unknown(0b1000);
|
||||
let unknown_bits = unknown.bits();
|
||||
assert_eq!(unknown_bits, 0b1000);
|
||||
|
||||
assert_eq!(known.unknown_bits(), 0b0000);
|
||||
assert_eq!(unknown.known_bits(), 0b0000);
|
||||
|
||||
assert_eq!((known | unknown).bits(), (known_bits | unknown_bits));
|
||||
assert_eq!((known | unknown).known_bits(), known_bits);
|
||||
assert_eq!((known | unknown).unknown_bits(), unknown_bits);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_is_empty() {
|
||||
assert!(Flags::empty().is_empty());
|
||||
@ -1080,6 +1149,22 @@ mod tests {
|
||||
assert_eq!(m4, AnotherSetOfFlags::empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_operators_unknown() {
|
||||
let unknown = Flags::from_bits_unknown(0b1000);
|
||||
let e1 = Flags::A | Flags::C | unknown;
|
||||
let e2 = Flags::B | Flags::C;
|
||||
assert_eq!((e1 | e2), (Flags::ABC | unknown)); // union
|
||||
assert_eq!((e1 & e2), Flags::C); // intersection
|
||||
assert_eq!((e1 - e2), (Flags::A | unknown)); // set difference
|
||||
assert_eq!(!e2, Flags::A); // set complement
|
||||
assert_eq!(!e1, Flags::B); // set complement
|
||||
assert_eq!(e1 ^ e2, Flags::A | Flags::B | unknown); // toggle
|
||||
let mut e3 = e1;
|
||||
e3.toggle(e2);
|
||||
assert_eq!(e3, Flags::A | Flags::B | unknown);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_set() {
|
||||
let mut e1 = Flags::A | Flags::C;
|
||||
@ -1203,30 +1288,46 @@ mod tests {
|
||||
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 unknown = Flags::from_bits_unknown(0xb8);
|
||||
assert_eq!(format!("{:?}", unknown), "0xb8");
|
||||
assert_eq!(format!("{:?}", Flags::A | unknown), "A | 0xb8");
|
||||
assert_eq!(format!("{:?}", Flags::ABC | unknown), "A | B | C | ABC | 0xb8");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_binary() {
|
||||
assert_eq!(format!("{:b}", Flags::ABC), "111");
|
||||
assert_eq!(format!("{:#b}", Flags::ABC), "0b111");
|
||||
let unknown = Flags::from_bits_unknown(0b1010000);
|
||||
assert_eq!(format!("{:b}", Flags::ABC | unknown), "1010111");
|
||||
assert_eq!(format!("{:#b}", Flags::ABC | unknown), "0b1010111");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_octal() {
|
||||
assert_eq!(format!("{:o}", LongFlags::LONG_A), "177777");
|
||||
assert_eq!(format!("{:#o}", LongFlags::LONG_A), "0o177777");
|
||||
let unknown = LongFlags::from_bits_unknown(0o5000000);
|
||||
assert_eq!(format!("{:o}", LongFlags::LONG_A | unknown), "5177777");
|
||||
assert_eq!(format!("{:#o}", LongFlags::LONG_A | unknown), "0o5177777");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_lowerhex() {
|
||||
assert_eq!(format!("{:x}", LongFlags::LONG_A), "ffff");
|
||||
assert_eq!(format!("{:#x}", LongFlags::LONG_A), "0xffff");
|
||||
let unknown = LongFlags::from_bits_unknown(0xe00000);
|
||||
assert_eq!(format!("{:x}", LongFlags::LONG_A | unknown), "e0ffff");
|
||||
assert_eq!(format!("{:#x}", LongFlags::LONG_A | unknown), "0xe0ffff");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_upperhex() {
|
||||
assert_eq!(format!("{:X}", LongFlags::LONG_A), "FFFF");
|
||||
assert_eq!(format!("{:#X}", LongFlags::LONG_A), "0xFFFF");
|
||||
let unknown = LongFlags::from_bits_unknown(0xe00000);
|
||||
assert_eq!(format!("{:X}", LongFlags::LONG_A | unknown), "E0FFFF");
|
||||
assert_eq!(format!("{:#X}", LongFlags::LONG_A | unknown), "0xE0FFFF");
|
||||
}
|
||||
|
||||
mod submodule {
|
||||
|
Loading…
Reference in New Issue
Block a user