pub trait Contains<Rhs> {
fn contains(&self, rhs: Rhs) -> bool;
}
macro_rules! flag_wrapper {
($clazz: ident, $single_flag: ty, $raw_type: ty) => {
#[derive(Clone, Copy, Debug, serde::Serialize)]
pub struct $clazz {
flags: enumflags2::BitFlags<$single_flag, $raw_type>,
original_value: Option<$raw_type>,
}
impl $clazz {
pub const EMPTY: Self = Self {
flags: enumflags2::BitFlags::<$single_flag, $raw_type>::EMPTY,
original_value: None,
};
pub fn empty() -> Self {
Self {
flags: enumflags2::BitFlags::<$single_flag, $raw_type>::empty(),
original_value: None,
}
}
pub const fn from_bitflags(
bitflags: enumflags2::BitFlags<$single_flag, $raw_type>,
) -> Self {
Self {
flags: bitflags,
original_value: None,
}
}
pub fn from_bitflag(bitflag: $single_flag) -> Self {
Self {
flags: enumflags2::BitFlags::<$single_flag, $raw_type>::EMPTY | bitflag,
original_value: None,
}
}
pub fn raw_value(&self) -> $raw_type {
self.flags.bits()
}
}
impl Contains<$single_flag> for $clazz {
fn contains(&self, bitflag: $single_flag) -> bool {
self.flags.contains(bitflag)
}
}
impl Contains<enumflags2::BitFlags::<$single_flag, $raw_type>> for $clazz {
fn contains(&self, bitflag: enumflags2::BitFlags::<$single_flag, $raw_type>) -> bool {
self.flags.contains(bitflag)
}
}
impl From<$raw_type> for $clazz {
fn from(value: $raw_type) -> Self {
let flags =
enumflags2::BitFlags::<$single_flag, $raw_type>::from_bits_truncate(value);
Self {
flags,
original_value: Some(value),
}
}
}
impl AsRef<enumflags2::BitFlags<$single_flag, $raw_type>> for $clazz {
fn as_ref(&self) -> &enumflags2::BitFlags<$single_flag, $raw_type> {
&self.flags
}
}
impl From<enumflags2::BitFlags<$single_flag, $raw_type>> for $clazz {
fn from(flags: enumflags2::BitFlags<$single_flag, $raw_type>) -> Self {
Self {
flags,
original_value: None,
}
}
}
impl std::ops::BitOr for $clazz {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output {
let flags = self.flags | rhs.flags;
let original_value = match (self.original_value, rhs.original_value) {
(None, None) => None,
(Some(lhs), Some(rhs)) => Some(lhs | rhs),
(Some(lhs), None) => Some(lhs | rhs.flags.bits()),
(None, Some(rhs)) => Some(self.flags.bits() | rhs),
};
Self {
flags,
original_value,
}
}
}
impl std::ops::BitOr<$single_flag> for $clazz {
type Output = Self;
fn bitor(self, rhs: $single_flag) -> Self::Output {
let flags = self.flags | rhs;
let original_value = match self.original_value {
Some(lhs) => Some(lhs | Self::from_bitflag(rhs).flags.bits()),
None => None,
};
Self {
flags,
original_value,
}
}
}
impl std::ops::BitOrAssign<$clazz> for $clazz {
fn bitor_assign(&mut self, rhs: $clazz) {
self.flags = self.flags | rhs.flags;
self.original_value = match (self.original_value, rhs.original_value) {
(None, None) => None,
(Some(lhs), Some(rhs)) => Some(lhs | rhs),
(Some(lhs), None) => Some(lhs | rhs.flags.bits()),
(None, Some(rhs)) => Some(self.flags.bits() | rhs),
};
}
}
impl std::ops::BitOrAssign<$single_flag> for $clazz {
fn bitor_assign(&mut self, rhs: $single_flag) {
self.flags = self.flags | rhs;
self.original_value = match self.original_value {
Some(lhs) => Some(lhs | Self::from_bitflag(rhs).flags.bits()),
None => None,
};
}
}
impl PartialEq for $clazz {
fn eq(&self, other: &Self) -> bool {
if self.flags == other.flags {
match (self.original_value, other.original_value) {
(None, None) => true,
(Some(lhs), None) => self.flags.bits() == lhs,
(None, Some(rhs)) => rhs == other.flags.bits(),
(Some(lhs), Some(rhs)) => lhs == rhs
}
} else {
false
}
}
}
impl Eq for $clazz {
}
impl BinRead for $clazz {
type Args<'a> = ();
fn read_options<R: std::io::Read + std::io::Seek>(
reader: &mut R,
endian: binrw::Endian,
args: Self::Args<'_>,
) -> binrw::BinResult<Self> {
let raw_value: $raw_type = reader.read_type_args(endian, args)?;
Ok(Self::from(raw_value))
}
}
impl BinWrite for $clazz {
type Args<'a> = ();
fn write_options<W: std::io::Write + std::io::Seek>(
&self,
writer: &mut W,
_endian: binrw::Endian,
args: Self::Args<'_>,
) -> binrw::BinResult<()> {
let value = self.original_value.unwrap_or(self.flags.bits());
writer.write_le_args(&value, args)
}
}
};
}
pub(crate) use flag_wrapper;