#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
pub struct MessageFlag(i32);
impl MessageFlag {
pub const NONE: Self = Self(0);
pub const COMPRESSED: Self = Self(1 << 0);
pub const MULTI_TAGS: Self = Self(1 << 1);
pub const TRANSACTION_PREPARED: Self = Self(1 << 2);
pub const TRANSACTION_COMMIT: Self = Self(1 << 3);
pub const TRANSACTION_ROLLBACK: Self = Self(1 << 4);
#[inline]
pub const fn empty() -> Self {
Self(0)
}
#[inline]
pub const fn from_bits(bits: i32) -> Self {
Self(bits)
}
#[inline]
pub const fn bits(&self) -> i32 {
self.0
}
#[inline]
pub const fn contains(&self, other: Self) -> bool {
(self.0 & other.0) == other.0
}
#[inline]
pub fn insert(&mut self, other: Self) {
self.0 |= other.0;
}
#[inline]
pub fn remove(&mut self, other: Self) {
self.0 &= !other.0;
}
#[inline]
pub fn is_compressed(&self) -> bool {
self.contains(Self::COMPRESSED)
}
#[inline]
pub fn is_multi_tags(&self) -> bool {
self.contains(Self::MULTI_TAGS)
}
#[inline]
pub fn is_transaction_prepared(&self) -> bool {
self.contains(Self::TRANSACTION_PREPARED)
}
#[inline]
pub fn is_transaction_commit(&self) -> bool {
self.contains(Self::TRANSACTION_COMMIT)
}
#[inline]
pub fn is_transaction_rollback(&self) -> bool {
self.contains(Self::TRANSACTION_ROLLBACK)
}
}
impl std::ops::BitOr for MessageFlag {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
Self(self.0 | rhs.0)
}
}
impl std::ops::BitOrAssign for MessageFlag {
fn bitor_assign(&mut self, rhs: Self) {
self.0 |= rhs.0;
}
}
impl std::ops::BitAnd for MessageFlag {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output {
Self(self.0 & rhs.0)
}
}
impl std::ops::BitAndAssign for MessageFlag {
fn bitand_assign(&mut self, rhs: Self) {
self.0 &= rhs.0;
}
}
impl From<i32> for MessageFlag {
fn from(value: i32) -> Self {
Self(value)
}
}
impl From<MessageFlag> for i32 {
fn from(flag: MessageFlag) -> Self {
flag.0
}
}
#[cfg(test)]
mod tests {
use super::MessageFlag;
#[test]
fn named_flags_compose_and_preserve_other_bits() {
let combined = MessageFlag::COMPRESSED | MessageFlag::MULTI_TAGS;
assert!(combined.is_compressed());
assert!(combined.is_multi_tags());
let mut flags = MessageFlag::COMPRESSED;
flags |= MessageFlag::MULTI_TAGS;
assert_eq!(flags, combined);
flags.remove(MessageFlag::COMPRESSED);
assert_eq!(flags, MessageFlag::MULTI_TAGS);
flags.insert(MessageFlag::COMPRESSED);
assert_eq!(flags, combined);
let mask = MessageFlag::MULTI_TAGS | MessageFlag::TRANSACTION_PREPARED;
assert_eq!(flags & mask, MessageFlag::MULTI_TAGS);
flags &= mask;
assert_eq!(flags, MessageFlag::MULTI_TAGS);
}
#[test]
fn unknown_bits_survive_named_flag_changes_and_conversion() {
let unknown = 1 << 30;
let mut flags = MessageFlag::from_bits(unknown);
flags.insert(MessageFlag::COMPRESSED);
assert_eq!(flags.bits(), unknown | MessageFlag::COMPRESSED.bits());
flags.remove(MessageFlag::COMPRESSED);
assert_eq!(flags.bits(), unknown);
let raw = i32::from(flags);
assert_eq!(raw, unknown);
assert_eq!(MessageFlag::from(raw), flags);
}
}