#[doc = crate::_tags!(construction set bit)]
#[doc = crate::_doc_meta!{location("data/codec")}]
#[doc = include_str!["./_docs_set.md"]]
#[macro_export]
#[cfg_attr(cargo_primary_package, doc(hidden))]
macro_rules! set· {
{
$(#[$struct_attrs:meta])*
$vis:vis struct $Set:ident($T:ty) {
$(
$(#[$f_attrs:meta])*
$f:ident = $( $start:tt $(..= $end:tt)? ),+ $(,)?;
)*
}
$( traits( $( ! $no_trait:ident ),* $(,)? ); )?
$( $(#[$impl_attrs:meta])*
impl { $($user_impl:item)* }
)*
} => {
$crate::set!(%guard_allowed_type $Set, $T);
$( #[$struct_attrs] )*
#[derive(Clone, Copy)]
$vis struct $Set { bits: $T }
$(
$( #[$impl_attrs] )*
impl $Set { $($user_impl)* }
)*
impl $Set { $crate::paste! { $(
#[$crate::compile[all(none($($($end)?)+), xone($(some($start)),+))]]
$crate::items! {
$(#[$f_attrs])*
#[allow(non_upper_case_globals)]
$vis const $f: Self = Self {
bits: $crate::set!(%mask $T; $( $start $(..= $end)? ),+)
};
}
#[$crate::compile[any(some($($($end)?)+), not(xone($(some($start)),+)))]]
$crate::items! {
$(#[$f_attrs])*
#[allow(non_upper_case_globals)]
$vis const $f: Self = Self {
bits: $crate::set!(%mask $T; $( $start $(..= $end)? ),+)
};
}
#[allow(non_upper_case_globals)]
pub(crate) const [<_ $f _BITS>]: u32 = Self::$f.bits.count_ones();
)* }}
#[allow(dead_code)]
impl $Set { $crate::paste! { $(
#[$crate::compile[all(none($($($end)?)+), xone($(some($start)),+))]]
$crate::items! {
#[doc = "Returns `true` if [`" $f "`][Self::" $f "] is present."]
$vis const fn [<has_ $f:lower>](self) -> bool { self.contains(Self::$f) }
#[doc = "Returns `true` if all bits in `" $f "` are present."]
$vis const fn [<contains_ $f:lower>](self) -> bool { self.contains(Self::$f) }
}
#[$crate::compile[any(some($($($end)?)+), not(xone($(some($start)),+)))]]
$crate::items! {
#[doc = "Returns `true` if the set contains all bits in [`" $f "`][Self::" $f "]."]
$vis const fn [<contains_ $f:lower>](self) -> bool { self.contains(Self::$f) }
}
#[doc = "Returns `true` if the set shares any bit with `" $f "`."]
$vis const fn [<intersects_ $f:lower>](self) -> bool { self.intersects(Self::$f) }
#[doc = "Returns `self` with `" $f "` inserted."]
$vis const fn [<with_ $f:lower>](self) -> Self { self.with(Self::$f) }
#[doc = "Returns `self` with `" $f "` inserted if `condition` is true."]
$vis const fn [<with_ $f:lower _if>](self, condition: bool) -> Self {
self.with_if(condition, Self::$f) }
#[doc = "Returns `self` with `" $f "` removed."]
$vis const fn [<without_ $f:lower>](self) -> Self { self.without(Self::$f) }
#[doc = "Sets `" $f "`."]
$vis const fn [<set_ $f:lower>](&mut self) { self.insert(Self::$f); }
#[doc = "Sets `" $f "` if `condition` is true."]
$vis const fn [<set_ $f:lower _if>](&mut self, condition: bool) {
if condition { self.insert(Self::$f); } }
#[doc = "Unsets `" $f "`."]
$vis const fn [<unset_ $f:lower>](&mut self) { self.remove(Self::$f); }
)* }}
#[allow(clippy::double_must_use, dead_code)]
impl $Set {
pub(crate) const _SET_BIT_WIDTH: usize = {
let bits = Self::all().bits;
if bits == 0 { 1 } else { (<$T>::BITS - bits.leading_zeros()) as usize }
};
pub(crate) const _SET_BIT_SIZE: usize = {
let bits = Self::all().bits;
if bits == 0 { 0 } else { (<$T>::BITS - bits.leading_zeros()) as usize }
};
pub(crate) const _SET_OCTAL_WIDTH: usize = Self::_SET_BIT_WIDTH.div_ceil(3);
pub(crate) const _SET_HEX_WIDTH: usize = Self::_SET_BIT_WIDTH.div_ceil(4);
#[must_use]
$vis const fn new() -> Self { Self { bits: 0 } }
#[must_use]
$vis const fn from_bits(bits: $T) -> Self { Self { bits } }
#[must_use]
$vis const fn bits(self) -> $T { self.bits }
#[must_use]
$vis const fn all() -> Self { Self { bits: 0 $(| Self::$f.bits)* } }
#[must_use]
$vis const fn is_empty(self) -> bool { self.bits == 0 }
#[must_use]
$vis const fn is_full(self) -> bool { self.bits == Self::all().bits }
#[must_use]
$vis const fn contains(self, other: Self) -> bool { self.is_superset(other) }
#[must_use]
$vis const fn has(self, other: Self) -> bool { self.contains(other) }
#[must_use]
$vis const fn with(self, other: Self) -> Self {
Self { bits: self.bits | other.bits }
}
#[must_use]
$vis const fn with_if(self, condition: bool, other: Self) -> Self {
if condition { Self { bits: self.bits | other.bits } } else { self }
}
#[must_use]
$vis const fn without(self, other: Self) -> Self {
Self { bits: self.bits & !other.bits }
}
#[must_use]
$vis const fn toggled(self, other: Self) -> Self {
Self { bits: self.bits ^ other.bits }
}
}
#[allow(clippy::double_must_use, dead_code)]
impl $Set {
$vis const fn intersects(self, other: Self) -> bool {
(self.bits & other.bits) != 0
}
$vis const fn is_subset(self, other: Self) -> bool {
(self.bits & other.bits) == self.bits
}
$vis const fn is_superset(self, other: Self) -> bool {
(self.bits & other.bits) == other.bits
}
#[must_use]
$vis const fn union(self, other: Self) -> Self {
Self { bits: self.bits | other.bits }
}
#[must_use]
$vis const fn intersection(self, other: Self) -> Self {
Self { bits: self.bits & other.bits }
}
#[must_use]
$vis const fn difference(self, other: Self) -> Self {
Self { bits: self.bits & !other.bits }
}
#[must_use]
$vis const fn symmetric_difference(self, other: Self) -> Self {
Self { bits: self.bits ^ other.bits }
}
}
#[allow(dead_code)]
impl $Set {
$vis const fn clear(&mut self) { self.bits = 0; }
$vis const fn insert(&mut self, other: Self) { self.bits |= other.bits; }
$vis const fn remove(&mut self, other: Self) { self.bits &= !other.bits; }
$vis const fn toggle(&mut self, other: Self) { self.bits ^= other.bits; }
}
$( #[$crate::compile[nota(PartialEq $(, $no_trait)*)]] )?
impl ::core::cmp::PartialEq for $Set {
fn eq(&self, other: &Self) -> bool { self.bits == other.bits }
}
$( #[$crate::compile[all(nota(Eq $(, $no_trait)*), nota(PartialEq $(, $no_trait)*))]] )?
impl ::core::cmp::Eq for $Set {}
$( #[$crate::compile[nota(PartialOrd $(, $no_trait)*)]] )?
#[allow(clippy::non_canonical_partial_ord_impl, reason = "would always need Ord")]
impl ::core::cmp::PartialOrd for $Set {
fn partial_cmp(&self, other: &Self) -> Option<::core::cmp::Ordering> {
self.bits.partial_cmp(&other.bits) }
}
$( #[$crate::compile[all(
nota(Ord $(, $no_trait)*),
nota(PartialOrd $(, $no_trait)*),
nota(Eq $(, $no_trait)*),
nota(PartialEq $(, $no_trait)*)
)]] )?
impl ::core::cmp::Ord for $Set {
fn cmp(&self, other: &Self) -> ::core::cmp::Ordering {
self.bits.cmp(&other.bits)
}
}
$( #[$crate::compile[nota(Hash $(, $no_trait)*)]] )?
impl ::core::hash::Hash for $Set {
fn hash<H: ::core::hash::Hasher>(&self, state: &mut H) {
self.bits.hash(state)
}
}
impl $crate::BitSized<{ $Set::_SET_BIT_SIZE }> for $Set {}
impl $crate::ConstInit for $Set { const INIT: Self = Self::new(); }
$( #[$crate::compile[nota(Default $(, $no_trait)*)]] )?
impl Default for $Set { fn default() -> Self { Self::new() } }
$crate::impl_trait! { fmt::Debug for
$( #[$crate::compile[nota(Debug $(, $no_trait)*)]] )?
$Set |self, f| write!(f, concat!(stringify!($Set),
"(0b{:0w$b})"), self.bits, w = Self::_SET_BIT_WIDTH) }
$crate::impl_trait! { fmt::Display for
$( #[$crate::compile[nota(Display $(, $no_trait)*)]] )?
$Set |self, f| write!(f, "0b{:0w$b}", self.bits, w = Self::_SET_BIT_WIDTH)
}
$crate::impl_trait! { fmt::Binary for
$( #[$crate::compile[nota(Binary $(, $no_trait)*)]] )?
$Set |self, f|
if f.alternate() { write!(f, "0b{:0w$b}", self.bits, w = Self::_SET_BIT_WIDTH) }
else { write!(f, "{:0w$b}", self.bits, w = Self::_SET_BIT_WIDTH) }
}
$crate::impl_trait! { fmt::Octal for
$( #[$crate::compile[nota(Octal $(, $no_trait)*)]] )?
$Set |self, f|
if f.alternate() { write!(f, "0o{:0w$o}", self.bits, w = Self::_SET_OCTAL_WIDTH) }
else { write!(f, "{:0w$o}", self.bits, w = Self::_SET_OCTAL_WIDTH) }
}
$crate::impl_trait! { fmt::LowerHex for
$( #[$crate::compile[nota(LowerHex $(, $no_trait)*)]] )?
$Set |self, f|
if f.alternate() { write!(f, "0x{:0w$x}", self.bits, w = Self::_SET_HEX_WIDTH) }
else { write!(f, "{:0w$x}", self.bits, w = Self::_SET_HEX_WIDTH) }
}
$crate::impl_trait! { fmt::UpperHex for
$( #[$crate::compile[nota(UpperHex $(, $no_trait)*)]] )?
$Set |self, f|
if f.alternate() { write!(f, "0x{:0w$X}", self.bits, w = Self::_SET_HEX_WIDTH) }
else { write!(f, "{:0w$X}", self.bits, w = Self::_SET_HEX_WIDTH) }
}
$( #[$crate::compile[nota(DebugExt $(, $no_trait)*)]] )?
impl $crate::DebugExt for $Set where $Set: $crate::Debug {
type Ctx = $crate::ReprMode;
fn fmt_with(&self, f: &mut $crate::Formatter<'_>, ctx: &Self::Ctx)
-> $crate::FmtResult<()> {
match ctx {
$crate::ReprMode::Raw => $crate::Debug::fmt(self, f),
$crate::ReprMode::Named => { self._fmt_named(f) }
$crate::ReprMode::RawNamed => {
write!(f, concat!(stringify!($Set), "("))?;
write!(f, "0b{:0width$b}", self.bits, width = Self::_SET_BIT_WIDTH)?;
write!(f, "; ")?;
self._fmt_named_inner(f)?;
write!(f, ")")
}
}
}
}
impl $Set {
fn _fmt_named(&self, f: &mut $crate::Formatter<'_>) -> $crate::FmtResult<()> {
write!(f, concat!(stringify!($Set), "("))?;
self._fmt_named_inner(f)?;
write!(f, ")")
}
fn _fmt_named_inner(&self, f: &mut $crate::Formatter<'_>) -> $crate::FmtResult<()> {
let mut first = true;
$crate::paste! { $(
if $crate::cif![all(none($($($end)?)+), xone($(some($start)),+))]
&& self.contains(Self::$f)
{
if !first { write!(f, " | ")?; }
write!(f, stringify!($f))?;
first = false;
}
)* }
if first { write!(f, "empty")?; }
Ok(())
}
}
impl ::core::ops::BitOr for $Set {
type Output = Self;
fn bitor(self, rhs: Self) -> Self::Output { self.union(rhs) }
}
impl ::core::ops::BitOrAssign for $Set {
fn bitor_assign(&mut self, rhs: Self) { self.insert(rhs); }
}
impl ::core::ops::BitAnd for $Set {
type Output = Self;
fn bitand(self, rhs: Self) -> Self::Output { self.intersection(rhs) }
}
impl ::core::ops::BitAndAssign for $Set {
fn bitand_assign(&mut self, rhs: Self) { *self = self.intersection(rhs); }
}
impl ::core::ops::Sub for $Set {
type Output = Self;
fn sub(self, rhs: Self) -> Self::Output { self.difference(rhs) }
}
impl ::core::ops::SubAssign for $Set {
fn sub_assign(&mut self, rhs: Self) { self.remove(rhs); }
}
impl ::core::ops::BitXor for $Set {
type Output = Self;
fn bitxor(self, rhs: Self) -> Self::Output { self.symmetric_difference(rhs) }
}
impl ::core::ops::BitXorAssign for $Set {
fn bitxor_assign(&mut self, rhs: Self) { self.toggle(rhs); }
}
impl ::core::ops::Not for $Set {
type Output = Self;
fn not(self) -> Self::Output { Self::all().difference(self) }
}
};
(%mask $T:ty; $($start:tt $(..= $end:tt)?),+ $(,)?) => {{
0 as $T $(| $crate::set!(%item $T; $start $(..= $end)?))+
}};
(%item $T:ty; $bit:tt) => {
$crate::Bitwise::<$T>::mask_range(($bit) as u32, ($bit) as u32).0
};
(%item $T:ty; $start:tt ..= $end:tt) => {
$crate::Bitwise::<$T>::mask_range(($start) as u32, ($end) as u32).0
};
(%guard_allowed_type $Set:ident, $T:ty) => { $crate::paste! {
const [<__GUARD_ALLOWED_TYPE_ $Set:upper>]: () = {
const fn __allowed_types<P: $crate::PrimUint>() {}
__allowed_types::<$T>();
};
}};
($($tt:tt)*) => { compile_error! { concat![
"set!: wrong syntax.\n\n",
"Expected:\n",
" set! { $vis struct Name($ty) { CONST = bits; ... } }\n\n",
"Examples of constant syntax:\n",
" SPACE = b' ';\n",
" HWS = b' ', b'\\t';\n",
" DIGIT = b'0'..=b'9';\n",
" ALNUM = b'0'..=b'9', b'A'..=b'Z', b'a'..=b'z';",
]}};
}
#[doc(inline)]
pub use set· as set;