use core::{
fmt::{Debug, Display},
hash::Hash,
mem::transmute,
ops::{BitAnd, BitAndAssign, BitOr, BitOrAssign, BitXor, BitXorAssign, Not},
panic::{RefUnwindSafe, UnwindSafe},
};
use crate::{
Aligned, Alignment, Length, Scalar, SupportedLength, Unaligned, Vector,
backend::MaskBackend,
utils::{specialize, transmute_generic, transmute_mut},
};
#[repr(transparent)]
pub struct Mask<const N: usize, T, A: Alignment>(
#[expect(clippy::type_complexity)]
pub(crate) <A as Alignment>::Select<
<Length<N> as SupportedLength>::Select<
<T as MaskBackend<2, Aligned>>::Inner,
<T as MaskBackend<3, Aligned>>::Inner,
<T as MaskBackend<4, Aligned>>::Inner,
>,
<Length<N> as SupportedLength>::Select<
<T as MaskBackend<2, Unaligned>>::Inner,
<T as MaskBackend<3, Unaligned>>::Inner,
<T as MaskBackend<4, Unaligned>>::Inner,
>,
>,
)
where
Length<N>: SupportedLength,
T: Scalar;
pub type Mask2<T> = Mask<2, T, Unaligned>;
pub type Mask3<T> = Mask<3, T, Unaligned>;
pub type Mask4<T> = Mask<4, T, Unaligned>;
pub type Mask2A<T> = Mask<2, T, Aligned>;
pub type Mask3A<T> = Mask<3, T, Aligned>;
pub type Mask4A<T> = Mask<4, T, Aligned>;
impl<const N: usize, T, A: Alignment> Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
#[inline]
#[must_use]
pub fn from_array(array: [bool; N]) -> Self {
specialize!(<T as MaskBackend<N, A>>::mask_from_array(array))
}
#[inline]
#[must_use]
pub fn splat(value: bool) -> Self {
specialize!(<T as MaskBackend<N, A>>::mask_splat(value))
}
#[inline]
#[must_use]
#[track_caller]
pub fn from_fn<F>(mut f: F) -> Self
where
F: FnMut(usize) -> bool,
{
unsafe {
match N {
2 => transmute_generic::<Mask<2, T, A>, Mask<N, T, A>>(Mask::<2, T, A>::new(
f(0),
f(1),
)),
3 => transmute_generic::<Mask<3, T, A>, Mask<N, T, A>>(Mask::<3, T, A>::new(
f(0),
f(1),
f(2),
)),
4 => transmute_generic::<Mask<4, T, A>, Mask<N, T, A>>(Mask::<4, T, A>::new(
f(0),
f(1),
f(2),
f(3),
)),
_ => unreachable!(),
}
}
}
#[inline]
#[must_use]
pub fn to_alignment<A2: Alignment>(self) -> Mask<N, T, A2> {
(const {
if A::IS_ALIGNED == A2::IS_ALIGNED {
unsafe {
transmute::<
fn(Mask<N, T, A>) -> Mask<N, T, A>,
fn(Mask<N, T, A>) -> Mask<N, T, A2>,
>(|mask| mask)
}
} else {
|mask: Self| Mask::from_array(mask.to_array())
}
})(self)
}
#[inline]
#[must_use]
pub fn align(self) -> Mask<N, T, Aligned> {
self.to_alignment()
}
#[inline]
#[must_use]
pub fn unalign(self) -> Mask<N, T, Unaligned> {
self.to_alignment()
}
#[inline]
#[must_use]
pub fn to_array(self) -> [bool; N] {
specialize!(<T as MaskBackend<N, A>>::mask_to_array(self))
}
#[inline]
#[must_use]
pub fn all(self) -> bool {
specialize!(<T as MaskBackend<N, A>>::mask_all(self))
}
#[inline]
#[must_use]
pub fn any(self) -> bool {
specialize!(<T as MaskBackend<N, A>>::mask_any(self))
}
#[inline]
#[must_use]
pub fn select(self, if_true: Vector<N, T, A>, if_false: Vector<N, T, A>) -> Vector<N, T, A> {
specialize!(<T as MaskBackend<N, A>>::mask_select(
self, if_true, if_false
))
}
#[inline]
#[must_use]
pub fn iter(self) -> core::array::IntoIter<bool, N> {
self.to_array().into_iter()
}
#[inline]
#[must_use]
#[track_caller]
pub fn get(self, index: usize) -> bool {
specialize!(<T as MaskBackend<N, A>>::mask_get(self, index))
}
#[inline]
#[track_caller]
pub fn set(&mut self, index: usize, value: bool) {
specialize!(<T as MaskBackend<N, A>>::mask_set(self, index, value))
}
#[inline]
#[must_use]
pub(crate) const fn from_inner(inner: <T as MaskBackend<N, A>>::Inner) -> Self
where
T: MaskBackend<N, A>,
{
unsafe { transmute_generic::<<T as MaskBackend<N, A>>::Inner, Mask<N, T, A>>(inner) }
}
#[inline]
#[must_use]
pub(crate) const fn inner(self) -> <T as MaskBackend<N, A>>::Inner
where
T: MaskBackend<N, A>,
{
unsafe { transmute_generic::<Mask<N, T, A>, <T as MaskBackend<N, A>>::Inner>(self) }
}
#[inline]
#[must_use]
pub(crate) const fn inner_mut(&mut self) -> &mut <T as MaskBackend<N, A>>::Inner
where
T: MaskBackend<N, A>,
{
unsafe { transmute_mut::<Mask<N, T, A>, <T as MaskBackend<N, A>>::Inner>(self) }
}
}
impl<T, A: Alignment> Mask<2, T, A>
where
T: Scalar,
{
#[inline]
#[must_use]
pub fn new(x: bool, y: bool) -> Self {
Self::from_array([x, y])
}
}
impl<T, A: Alignment> Mask<3, T, A>
where
T: Scalar,
{
#[inline]
#[must_use]
pub fn new(x: bool, y: bool, z: bool) -> Self {
Self::from_array([x, y, z])
}
}
impl<T, A: Alignment> Mask<4, T, A>
where
T: Scalar,
{
#[inline]
#[must_use]
pub fn new(x: bool, y: bool, z: bool, w: bool) -> Self {
Self::from_array([x, y, z, w])
}
}
impl<const N: usize, T, A: Alignment> Clone for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
#[inline]
fn clone(&self) -> Self {
*self
}
}
impl<const N: usize, T, A: Alignment> Copy for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
}
impl<const N: usize, T, A: Alignment> IntoIterator for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
type Item = bool;
type IntoIter = core::array::IntoIter<bool, N>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<const N: usize, T, A: Alignment> IntoIterator for &Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
type Item = bool;
type IntoIter = core::array::IntoIter<bool, N>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<const N: usize, T, A: Alignment> Debug for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{:?}", Vector::<N, bool, A>::from_array(self.to_array()))
}
}
impl<const N: usize, T, A: Alignment> Display for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
#[inline]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "{}", Vector::<N, bool, A>::from_array(self.to_array()))
}
}
impl<const N: usize, T, A: Alignment> PartialEq for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
#[inline]
fn eq(&self, other: &Self) -> bool {
specialize!(<T as MaskBackend<N, A>>::mask_eq(self, other))
}
#[expect(clippy::partialeq_ne_impl)]
#[inline]
fn ne(&self, other: &Self) -> bool {
specialize!(<T as MaskBackend<N, A>>::mask_ne(self, other))
}
}
impl<const N: usize, T, A: Alignment> Eq for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
}
impl<const N: usize, T, A: Alignment> Hash for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
#[inline]
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.to_array().hash(state);
}
}
impl<const N: usize, T, A: Alignment> Default for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
#[inline]
fn default() -> Self {
Self::splat(bool::default())
}
}
macro_rules! impl_not {
($(#[$doc:meta])*) => {
impl<const N: usize, T, A: Alignment> Not for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
type Output = Self;
$(#[$doc])*
#[inline]
fn not(self) -> Self::Output {
specialize!(<T as MaskBackend<N, A>>::mask_not(self))
}
}
impl<const N: usize, T, A: Alignment> Not for &Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
type Output = Mask<N, T, A>;
$(#[$doc])*
#[inline]
fn not(self) -> Self::Output {
Mask::not(*self)
}
}
};
}
impl_not!(
);
macro_rules! impl_binary_operator {
($Op:ident, $op:ident, $mask_op:ident, $(#[$doc:meta])*, $(#[$doc_scalar:meta])*) => {
impl<const N: usize, T, A: Alignment> $Op for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
type Output = Self;
$(#[$doc])*
#[inline]
fn $op(self, rhs: Self) -> Self::Output {
specialize!(<T as MaskBackend<N, A>>::$mask_op(self, rhs))
}
}
impl<const N: usize, T, A: Alignment> $Op<bool> for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
type Output = Self;
$(#[$doc_scalar])*
#[inline]
fn $op(self, rhs: bool) -> Self::Output {
self.$op(Self::splat(rhs))
}
}
impl<const N: usize, T, A: Alignment> $Op<&Mask<N, T, A>> for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
type Output = Self;
$(#[$doc])*
#[inline]
fn $op(self, rhs: &Mask<N, T, A>) -> Self::Output {
Self::$op(self, *rhs)
}
}
impl<const N: usize, T, A: Alignment> $Op<&bool> for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
type Output = Self;
$(#[$doc_scalar])*
#[inline]
fn $op(self, rhs: &bool) -> Self::Output {
self.$op(Self::splat(*rhs))
}
}
impl<const N: usize, T, A: Alignment> $Op<Mask<N, T, A>> for &Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
type Output = Mask<N, T, A>;
$(#[$doc])*
#[inline]
fn $op(self, rhs: Mask<N, T, A>) -> Self::Output {
Mask::$op(*self, rhs)
}
}
impl<const N: usize, T, A: Alignment> $Op<bool> for &Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
type Output = Mask<N, T, A>;
$(#[$doc_scalar])*
#[inline]
fn $op(self, rhs: bool) -> Self::Output {
Mask::$op(*self, Mask::splat(rhs))
}
}
impl<const N: usize, T, A: Alignment> $Op<&Mask<N, T, A>> for &Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
type Output = Mask<N, T, A>;
$(#[$doc])*
#[inline]
fn $op(self, rhs: &Mask<N, T, A>) -> Self::Output {
Mask::$op(*self, *rhs)
}
}
impl<const N: usize, T, A: Alignment> $Op<&bool> for &Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
type Output = Mask<N, T, A>;
$(#[$doc_scalar])*
#[inline]
fn $op(self, rhs: &bool) -> Self::Output {
Mask::$op(*self, Mask::splat(*rhs))
}
}
};
}
impl_binary_operator!(
BitAnd,
bitand,
mask_bitand,
,
);
impl_binary_operator!(
BitOr,
bitor,
mask_bitor,
,
);
impl_binary_operator!(
BitXor,
bitxor,
mask_bitxor,
,
);
macro_rules! impl_assign_operator {
($OpAssign:ident, $op_assign:ident, $op:ident, $(#[$doc:meta])*, $(#[$doc_scalar:meta])*) => {
impl<const N: usize, T, A: Alignment> $OpAssign for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
#[inline]
fn $op_assign(&mut self, rhs: Self) {
*self = self.$op(rhs);
}
}
impl<const N: usize, T, A: Alignment> $OpAssign<bool> for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
#[inline]
fn $op_assign(&mut self, rhs: bool) {
*self = self.$op(rhs);
}
}
impl<const N: usize, T, A: Alignment> $OpAssign<&Mask<N, T, A>> for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
#[inline]
fn $op_assign(&mut self, rhs: &Mask<N, T, A>) {
*self = self.$op(*rhs);
}
}
impl<const N: usize, T, A: Alignment> $OpAssign<&bool> for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
#[inline]
fn $op_assign(&mut self, rhs: &bool) {
*self = self.$op(*rhs);
}
}
};
}
impl_assign_operator!(
BitAndAssign,
bitand_assign,
bitand,
,
);
impl_assign_operator!(
BitOrAssign,
bitor_assign,
bitor,
,
);
impl_assign_operator!(
BitXorAssign,
bitxor_assign,
bitxor,
,
);
unsafe impl<const N: usize, T, A: Alignment> Send for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
}
unsafe impl<const N: usize, T, A: Alignment> Sync for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
}
impl<const N: usize, T, A: Alignment> Unpin for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
}
impl<const N: usize, T, A: Alignment> UnwindSafe for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
}
impl<const N: usize, T, A: Alignment> RefUnwindSafe for Mask<N, T, A>
where
Length<N>: SupportedLength,
T: Scalar,
{
}
#[cfg(test)]
mod tests {
extern crate std;
use std::{convert::identity, format, vec::Vec};
use crate::{
Aligned, Mask, Mask2, Mask3, Mask4, Unaligned, Vector,
test_utils::{assert_panic, for_types, random_iter},
utils::{Repr2, Repr3, Repr4},
};
#[test]
fn test_layout() {
for_types!(|N, T: PrimitiveNumber| {
assert!(
size_of::<Mask<N, T, Aligned>>() == N && align_of::<Mask<N, T, Aligned>>() == 1
|| size_of::<Mask<N, T, Aligned>>() == size_of::<Vector<N, T, Aligned>>()
&& align_of::<Mask<N, T, Aligned>>() == align_of::<Vector<N, T, Aligned>>()
);
assert_eq!(size_of::<Mask<N, T, Unaligned>>(), N);
assert_eq!(align_of::<Mask<N, T, Unaligned>>(), 1);
});
}
#[test]
fn test_from_array() {
for_types!(|T: PrimitiveNumber, A| {
for [x, y, z, w] in random_iter::<[bool; 4]>() {
assert_eq!(
Mask::<2, T, A>::from_array([x, y]),
Mask::<2, T, A>::new(x, y)
);
assert_eq!(
Mask::<3, T, A>::from_array([x, y, z]),
Mask::<3, T, A>::new(x, y, z)
);
assert_eq!(
Mask::<4, T, A>::from_array([x, y, z, w]),
Mask::<4, T, A>::new(x, y, z, w)
);
}
});
}
#[test]
fn test_splat() {
for_types!(|N, T: PrimitiveNumber, A| {
for x in random_iter() {
assert_eq!(Mask::<N, T, A>::splat(x), Mask::from_array([x; N]));
}
});
}
#[test]
fn test_from_fn() {
for_types!(|N, T: PrimitiveNumber, A| {
for array in random_iter::<[bool; N]>() {
assert_eq!(
Mask::<N, T, A>::from_fn(|i| array[i]),
Mask::from_array(array)
);
}
});
}
#[test]
fn test_to_alignment() {
for_types!(|N, T: PrimitiveNumber, A| {
for array in random_iter::<[bool; N]>() {
assert_eq!(
Mask::<N, T, A>::from_array(array).to_alignment(),
Mask::<N, T, Aligned>::from_array(array)
);
assert_eq!(
Mask::<N, T, A>::from_array(array).to_alignment(),
Mask::<N, T, Unaligned>::from_array(array)
);
}
});
}
#[test]
fn test_align() {
for_types!(|N, T: PrimitiveNumber, A| {
for array in random_iter::<[bool; N]>() {
assert_eq!(
Mask::<N, T, A>::from_array(array).align(),
Mask::<N, T, Aligned>::from_array(array)
);
}
});
}
#[test]
fn test_unalign() {
for_types!(|N, T: PrimitiveNumber, A| {
for array in random_iter::<[bool; N]>() {
assert_eq!(
Mask::<N, T, A>::from_array(array).unalign(),
Mask::<N, T, Unaligned>::from_array(array)
);
}
});
}
#[test]
fn test_to_array() {
for_types!(|N, T: PrimitiveNumber, A| {
for array in random_iter::<[bool; N]>() {
assert_eq!(Mask::<N, T, A>::from_array(array).to_array(), array);
}
});
}
#[test]
fn test_all() {
for_types!(|N, T: PrimitiveNumber, A| {
for mask in [Mask::splat(false), Mask::splat(true)]
.into_iter()
.chain(random_iter::<Mask<N, T, A>>())
{
assert_eq!(mask.all(), mask.iter().all(identity));
}
});
}
#[test]
fn test_any() {
for_types!(|N, T: PrimitiveNumber, A| {
for mask in [Mask::splat(false), Mask::splat(true)]
.into_iter()
.chain(random_iter::<Mask<N, T, A>>())
{
assert_eq!(mask.any(), mask.iter().any(identity));
}
});
}
#[test]
fn test_select() {
for_types!(|N, T: PrimitiveNumber, A| {
let if_true = Vector::<N, T, A>::from_fn(T::as_from);
let if_false = Vector::<N, T, A>::from_fn(|i| T::as_from(i + N));
for mask in random_iter::<Mask<N, T, A>>() {
assert_eq!(
mask.select(if_true, if_false),
Vector::from_fn(|i| if mask.get(i) { if_true[i] } else { if_false[i] })
);
}
});
}
#[test]
fn test_iter() {
for_types!(|N, T: PrimitiveNumber, A| {
for mask in random_iter::<Mask<N, T, A>>() {
assert_eq!(
mask.iter().collect::<Vec<bool>>(),
Vec::from(mask.to_array())
);
}
});
}
#[test]
fn test_get() {
for_types!(|N, T: PrimitiveNumber, A| {
for mask in random_iter::<Mask<N, T, A>>() {
for i in 0..N {
assert_eq!(mask.get(i), mask.to_array()[i]);
}
assert_panic!(mask.get(N));
assert_panic!(mask.get(N + 1));
}
});
}
#[test]
fn test_set() {
for_types!(|N, T: PrimitiveNumber, A| {
for mask in random_iter::<Mask<N, T, A>>() {
for value in [false, true] {
for i in 0..N {
let mut result = mask;
result.set(i, value);
let mut expected = mask.to_array();
expected[i] = value;
assert_eq!(result, Mask::from_array(expected));
}
assert_panic!(mask.clone().set(N, value));
assert_panic!(mask.clone().set(N + 1, value));
}
}
});
}
#[test]
fn test_from_inner() {
assert_eq!(
Mask2::<u32>::from_inner(Repr2(false, true)),
Mask2::new(false, true)
);
assert_eq!(
Mask3::<u32>::from_inner(Repr3(false, true, false)),
Mask3::new(false, true, false)
);
assert_eq!(
Mask4::<u32>::from_inner(Repr4(false, true, false, true)),
Mask4::new(false, true, false, true)
);
}
#[test]
fn test_inner() {
assert_eq!(Mask2::<u32>::new(false, true).inner(), Repr2(false, true));
assert_eq!(
Mask3::<u32>::new(false, true, false).inner(),
Repr3(false, true, false)
);
assert_eq!(
Mask4::<u32>::new(false, true, false, true).inner(),
Repr4(false, true, false, true)
);
}
#[test]
fn test_inner_mut() {
assert_eq!(
Mask2::<u32>::new(false, true).inner_mut(),
&mut Repr2(false, true)
);
assert_eq!(
Mask3::<u32>::new(false, true, false).inner_mut(),
&mut Repr3(false, true, false)
);
assert_eq!(
Mask4::<u32>::new(false, true, false, true).inner_mut(),
&mut Repr4(false, true, false, true)
);
}
#[test]
fn test_into_iter() {
for_types!(|N, T: PrimitiveNumber, A| {
for mask in random_iter::<Mask<N, T, A>>() {
assert_eq!(
mask.into_iter().collect::<Vec<bool>>(),
Vec::from(mask.to_array())
);
}
});
}
#[test]
fn test_debug() {
for_types!(|T: PrimitiveNumber, A| {
for [x, y, z, w] in random_iter::<[bool; 4]>() {
assert_eq!(
format!("{:?}", Mask::<2, T, A>::new(x, y)),
format!("({x:?}, {y:?})")
);
assert_eq!(
format!("{:?}", Mask::<3, T, A>::new(x, y, z)),
format!("({x:?}, {y:?}, {z:?})")
);
assert_eq!(
format!("{:?}", Mask::<4, T, A>::new(x, y, z, w)),
format!("({x:?}, {y:?}, {z:?}, {w:?})")
);
}
});
}
#[test]
fn test_display() {
for_types!(|T: PrimitiveNumber, A| {
for [x, y, z, w] in random_iter::<[bool; 4]>() {
assert_eq!(
format!("{}", Mask::<2, T, A>::new(x, y)),
format!("({x}, {y})")
);
assert_eq!(
format!("{}", Mask::<3, T, A>::new(x, y, z)),
format!("({x}, {y}, {z})")
);
assert_eq!(
format!("{}", Mask::<4, T, A>::new(x, y, z, w)),
format!("({x}, {y}, {z}, {w})")
);
}
});
}
#[test]
fn test_eq() {
for_types!(|N, T: PrimitiveNumber, A| {
for [mask_1, mask_2] in random_iter::<[Mask<N, T, A>; 2]>()
.chain(random_iter().map(|mask| [mask, mask]))
.chain(random_iter::<Mask<N, T, A>>().map(|mask| [mask, !mask]))
{
assert_eq!(mask_1 == mask_2, mask_1.to_array() == mask_2.to_array());
}
});
}
#[test]
fn test_ne() {
for_types!(|N, T: PrimitiveNumber, A| {
for [mask_1, mask_2] in random_iter::<[Mask<N, T, A>; 2]>()
.chain(random_iter().map(|mask| [mask, mask]))
.chain(random_iter::<Mask<N, T, A>>().map(|mask| [mask, !mask]))
{
assert_eq!(mask_1 != mask_2, mask_1.to_array() != mask_2.to_array());
}
});
}
#[test]
fn test_default() {
for_types!(|N, T: PrimitiveNumber, A| {
assert_eq!(Mask::<N, T, A>::default(), Mask::splat(bool::default()));
});
}
#[test]
fn test_not() {
for_types!(|N, T: PrimitiveNumber, A| {
for mask in random_iter::<Mask<N, T, A>>() {
assert_eq!(!mask, Mask::from_array(mask.to_array().map(|x| !x)));
}
});
}
#[test]
fn test_bitand() {
for_types!(|N, T: PrimitiveNumber, A| {
for [mask_1, mask_2] in random_iter::<[Mask<N, T, A>; 2]>() {
assert_eq!(
mask_1 & mask_2,
Mask::<N, T, A>::from_fn(|i| mask_1.get(i) & mask_2.get(i))
);
}
});
}
#[test]
fn test_bitor() {
for_types!(|N, T: PrimitiveNumber, A| {
for [mask_1, mask_2] in random_iter::<[Mask<N, T, A>; 2]>() {
assert_eq!(
mask_1 | mask_2,
Mask::<N, T, A>::from_fn(|i| mask_1.get(i) | mask_2.get(i))
);
}
});
}
#[test]
fn test_bitxor() {
for_types!(|N, T: PrimitiveNumber, A| {
for [mask_1, mask_2] in random_iter::<[Mask<N, T, A>; 2]>() {
assert_eq!(
mask_1 ^ mask_2,
Mask::<N, T, A>::from_fn(|i| mask_1.get(i) ^ mask_2.get(i))
);
}
});
}
#[test]
fn test_bitand_assign() {
for_types!(|N, T: PrimitiveNumber, A| {
for [mask_1, mask_2] in random_iter::<[Mask<N, T, A>; 2]>() {
let mut result = mask_1;
result &= mask_2;
assert_eq!(result, mask_1 & mask_2);
}
});
}
#[test]
fn test_bitor_assign() {
for_types!(|N, T: PrimitiveNumber, A| {
for [mask_1, mask_2] in random_iter::<[Mask<N, T, A>; 2]>() {
let mut result = mask_1;
result |= mask_2;
assert_eq!(result, mask_1 | mask_2);
}
});
}
#[test]
fn test_bitxor_assign() {
for_types!(|N, T: PrimitiveNumber, A| {
for [mask_1, mask_2] in random_iter::<[Mask<N, T, A>; 2]>() {
let mut result = mask_1;
result ^= mask_2;
assert_eq!(result, mask_1 ^ mask_2);
}
});
}
}