use std::fmt;
#[cfg(feature = "python")]
use pyo3::prelude::*;
pub const LAST: u8 = 1 << 7;
pub const TOB: u8 = 1 << 6;
pub const SNAPSHOT: u8 = 1 << 5;
pub const MBP: u8 = 1 << 4;
pub const BAD_TS_RECV: u8 = 1 << 3;
pub const MAYBE_BAD_BOOK: u8 = 1 << 2;
pub const PUBLISHER_SPECIFIC: u8 = 1 << 1;
#[repr(transparent)]
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Default, Hash)]
#[cfg_attr(feature = "python", derive(FromPyObject), pyo3(transparent))]
#[cfg_attr(
feature = "serde",
derive(serde::Serialize, serde::Deserialize),
serde(transparent)
)]
pub struct FlagSet {
raw: u8,
}
impl fmt::Debug for FlagSet {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut has_written_flag = false;
for (flag, name) in [
(LAST, stringify!(LAST)),
(TOB, stringify!(TOB)),
(SNAPSHOT, stringify!(SNAPSHOT)),
(MBP, stringify!(MBP)),
(BAD_TS_RECV, stringify!(BAD_TS_RECV)),
(MAYBE_BAD_BOOK, stringify!(MAYBE_BAD_BOOK)),
(PUBLISHER_SPECIFIC, stringify!(PUBLISHER_SPECIFIC)),
] {
if (self.raw() & flag) > 0 {
if has_written_flag {
write!(f, " | {name}")?;
} else {
write!(f, "{name}")?;
has_written_flag = true;
}
}
}
if has_written_flag {
write!(f, " ({})", self.raw())
} else {
write!(f, "{}", self.raw())
}
}
}
impl From<u8> for FlagSet {
fn from(raw: u8) -> Self {
Self { raw }
}
}
impl FlagSet {
pub const fn empty() -> Self {
Self { raw: 0 }
}
pub const fn new(raw: u8) -> Self {
Self { raw }
}
pub const fn clear(&mut self) -> &mut Self {
self.raw = 0;
self
}
pub const fn raw(&self) -> u8 {
self.raw
}
pub const fn set_raw(&mut self, raw: u8) {
self.raw = raw;
}
pub const fn any(&self) -> bool {
self.raw > 0
}
pub const fn is_empty(&self) -> bool {
self.raw == 0
}
pub const fn is_last(&self) -> bool {
(self.raw & LAST) > 0
}
pub const fn set_last(&mut self) -> Self {
self.raw |= LAST;
*self
}
pub const fn is_tob(&self) -> bool {
(self.raw & TOB) > 0
}
pub const fn set_tob(&mut self) -> Self {
self.raw |= TOB;
*self
}
pub const fn is_snapshot(&self) -> bool {
(self.raw & SNAPSHOT) > 0
}
pub const fn set_snapshot(&mut self) -> Self {
self.raw |= SNAPSHOT;
*self
}
pub const fn is_mbp(&self) -> bool {
(self.raw & MBP) > 0
}
pub const fn set_mbp(&mut self) -> Self {
self.raw |= MBP;
*self
}
pub const fn is_bad_ts_recv(&self) -> bool {
(self.raw & BAD_TS_RECV) > 0
}
pub const fn set_bad_ts_recv(&mut self) -> Self {
self.raw |= BAD_TS_RECV;
*self
}
pub const fn is_maybe_bad_book(&self) -> bool {
(self.raw & MAYBE_BAD_BOOK) > 0
}
pub const fn set_maybe_bad_book(&mut self) -> Self {
self.raw |= MAYBE_BAD_BOOK;
*self
}
pub const fn is_publisher_specific(&self) -> bool {
(self.raw & PUBLISHER_SPECIFIC) > 0
}
pub const fn set_publisher_specific(&mut self) -> Self {
self.raw |= PUBLISHER_SPECIFIC;
*self
}
}
#[cfg(test)]
mod tests {
use super::*;
use rstest::*;
#[rstest]
#[case::empty(FlagSet::empty(), "0")]
#[case::one_set(FlagSet::empty().set_mbp(), "MBP (16)")]
#[case::three_set(FlagSet::empty().set_tob().set_snapshot().set_maybe_bad_book(), "TOB | SNAPSHOT | MAYBE_BAD_BOOK (100)")]
#[case::reserved_set(
FlagSet::new(255),
"LAST | TOB | SNAPSHOT | MBP | BAD_TS_RECV | MAYBE_BAD_BOOK | PUBLISHER_SPECIFIC (255)"
)]
fn dbg(#[case] target: FlagSet, #[case] exp: &str) {
assert_eq!(format!("{target:?}"), exp);
}
}