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, ScalarRepr, SupportedLength, Unaligned, Vector,
utils::specialize,
};
#[repr(transparent)]
pub struct Mask<const N: usize, T, A: Alignment>(
pub(crate) <T::Repr as ScalarRepr>::MaskRepr<N, A>,
)
where
Length<N>: SupportedLength,
T: Scalar;
pub type Mask2<T> = Mask<2, T, Aligned>;
pub type Mask3<T> = Mask<3, T, Aligned>;
pub type Mask4<T> = Mask<4, T, Aligned>;
pub type Mask2U<T> = Mask<2, T, Unaligned>;
pub type Mask3U<T> = Mask<3, T, Unaligned>;
pub type Mask4U<T> = Mask<4, T, Unaligned>;
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::Repr as MaskBackend<N, A>>::mask_from_array(array))
}
#[inline]
#[must_use]
pub fn splat(value: bool) -> Self {
specialize!(<T::Repr as MaskBackend<N, A>>::mask_splat(value))
}
#[inline]
#[must_use]
#[track_caller]
pub fn from_fn<F>(f: F) -> Self
where
F: FnMut(usize) -> bool,
{
specialize!(<T::Repr as MaskBackend<N, A>>::mask_from_fn((f,)))
}
#[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::Repr as MaskBackend<N, A>>::mask_to_array(self))
}
#[inline]
#[must_use]
pub fn all(self) -> bool {
specialize!(<T::Repr as MaskBackend<N, A>>::mask_all(self))
}
#[inline]
#[must_use]
pub fn any(self) -> bool {
specialize!(<T::Repr 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::Repr 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::Repr as MaskBackend<N, A>>::mask_get(self, index))
}
#[inline]
#[track_caller]
pub fn set(&mut self, index: usize, value: bool) {
specialize!(<T::Repr as MaskBackend<N, A>>::mask_set(self, index, value))
}
#[inline]
#[must_use]
pub const fn to_repr<T2>(self) -> Mask<N, T2, A>
where
T2: Scalar<Repr = T::Repr>,
{
Mask(self.0)
}
}
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::Repr as MaskBackend<N, A>>::mask_eq(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::Repr 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::Repr 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,
{
}
pub(crate) trait MaskBackend<const N: usize, A: Alignment>
where
Length<N>: SupportedLength,
{
fn mask_from_array<T>(array: [bool; N]) -> Mask<N, T, A>
where
T: Scalar<Repr = Self>;
fn mask_splat<T>(value: bool) -> Mask<N, T, A>
where
T: Scalar<Repr = Self>;
fn mask_from_fn<T, F>(f: (F,)) -> Mask<N, T, A>
where
T: Scalar<Repr = Self>,
F: FnMut(usize) -> bool;
fn mask_to_array<T>(mask: Mask<N, T, A>) -> [bool; N]
where
T: Scalar<Repr = Self>;
fn mask_all<T>(mask: Mask<N, T, A>) -> bool
where
T: Scalar<Repr = Self>;
fn mask_any<T>(mask: Mask<N, T, A>) -> bool
where
T: Scalar<Repr = Self>;
fn mask_select<T>(
mask: Mask<N, T, A>,
if_true: Vector<N, T, A>,
if_false: Vector<N, T, A>,
) -> Vector<N, T, A>
where
T: Scalar<Repr = Self>;
#[track_caller]
fn mask_get<T>(mask: Mask<N, T, A>, index: usize) -> bool
where
T: Scalar<Repr = Self>;
#[track_caller]
fn mask_set<T>(mask: &mut Mask<N, T, A>, index: usize, value: bool)
where
T: Scalar<Repr = Self>;
fn mask_eq<T>(mask: &Mask<N, T, A>, other: &Mask<N, T, A>) -> bool
where
T: Scalar<Repr = Self>;
fn mask_not<T>(mask: Mask<N, T, A>) -> Mask<N, T, A>
where
T: Scalar<Repr = Self>;
fn mask_bitand<T>(mask: Mask<N, T, A>, rhs: Mask<N, T, A>) -> Mask<N, T, A>
where
T: Scalar<Repr = Self>;
fn mask_bitor<T>(mask: Mask<N, T, A>, rhs: Mask<N, T, A>) -> Mask<N, T, A>
where
T: Scalar<Repr = Self>;
fn mask_bitxor<T>(mask: Mask<N, T, A>, rhs: Mask<N, T, A>) -> Mask<N, T, A>
where
T: Scalar<Repr = Self>;
}
#[cfg(test)]
mod tests {
use itertools::Itertools;
use crate::{
Aligned, Mask, Mask2, Mask2U, Mask3, Mask3U, Mask4, Mask4U, Unaligned, Vec2, Vec3, Vec4,
Vector,
utils::{assert_panic, for_parameters},
};
#[test]
fn test_layout() {
for_parameters!(|T: PrimitiveNumber| {
assert!(
size_of::<Mask2<T>>() == 2 && align_of::<Mask2<T>>() == 1
|| size_of::<Mask2<T>>() == size_of::<Vec2<T>>()
&& align_of::<Mask2<T>>() == align_of::<Vec2<T>>()
);
assert!(
size_of::<Mask3<T>>() == 3 && align_of::<Mask3<T>>() == 1
|| size_of::<Mask3<T>>() == size_of::<Vec3<T>>()
&& align_of::<Mask3<T>>() == align_of::<Vec3<T>>()
);
assert!(
size_of::<Mask4<T>>() == 4 && align_of::<Mask4<T>>() == 1
|| size_of::<Mask4<T>>() == size_of::<Vec4<T>>()
&& align_of::<Mask4<T>>() == align_of::<Vec4<T>>()
);
assert_eq!(size_of::<Mask2U<T>>(), 2);
assert_eq!(align_of::<Mask2U<T>>(), 1);
assert_eq!(size_of::<Mask3U<T>>(), 3);
assert_eq!(align_of::<Mask3U<T>>(), 1);
assert_eq!(size_of::<Mask4U<T>>(), 4);
assert_eq!(align_of::<Mask4U<T>>(), 1);
});
}
#[test]
fn test_from_array() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
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_parameters!(|T: PrimitiveNumber, A, x| {
assert_eq!(Mask::<2, T, A>::splat(x), Mask::<2, T, A>::new(x, x));
assert_eq!(Mask::<3, T, A>::splat(x), Mask::<3, T, A>::new(x, x, x));
assert_eq!(Mask::<4, T, A>::splat(x), Mask::<4, T, A>::new(x, x, x, x));
});
}
#[test]
fn test_from_fn() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
assert_eq!(
Mask::<2, T, A>::from_fn(|i| [x, y][i]),
Mask::<2, T, A>::new(x, y)
);
assert_eq!(
Mask::<3, T, A>::from_fn(|i| [x, y, z][i]),
Mask::<3, T, A>::new(x, y, z)
);
assert_eq!(
Mask::<4, T, A>::from_fn(|i| [x, y, z, w][i]),
Mask::<4, T, A>::new(x, y, z, w)
);
});
}
#[test]
fn test_to_alignment() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
assert_eq!(
Mask::<2, T, A>::new(x, y).to_alignment(),
Mask::<2, T, Aligned>::new(x, y)
);
assert_eq!(
Mask::<3, T, A>::new(x, y, z).to_alignment(),
Mask::<3, T, Aligned>::new(x, y, z)
);
assert_eq!(
Mask::<4, T, A>::new(x, y, z, w).to_alignment(),
Mask::<4, T, Aligned>::new(x, y, z, w)
);
assert_eq!(
Mask::<2, T, A>::new(x, y).to_alignment(),
Mask::<2, T, Unaligned>::new(x, y)
);
assert_eq!(
Mask::<3, T, A>::new(x, y, z).to_alignment(),
Mask::<3, T, Unaligned>::new(x, y, z)
);
assert_eq!(
Mask::<4, T, A>::new(x, y, z, w).to_alignment(),
Mask::<4, T, Unaligned>::new(x, y, z, w)
);
});
}
#[test]
fn test_align() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
assert_eq!(
Mask::<2, T, A>::new(x, y).align(),
Mask::<2, T, Aligned>::new(x, y)
);
assert_eq!(
Mask::<3, T, A>::new(x, y, z).align(),
Mask::<3, T, Aligned>::new(x, y, z)
);
assert_eq!(
Mask::<4, T, A>::new(x, y, z, w).align(),
Mask::<4, T, Aligned>::new(x, y, z, w)
);
});
}
#[test]
fn test_unalign() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
assert_eq!(
Mask::<2, T, A>::new(x, y).unalign(),
Mask::<2, T, Unaligned>::new(x, y)
);
assert_eq!(
Mask::<3, T, A>::new(x, y, z).unalign(),
Mask::<3, T, Unaligned>::new(x, y, z)
);
assert_eq!(
Mask::<4, T, A>::new(x, y, z, w).unalign(),
Mask::<4, T, Unaligned>::new(x, y, z, w)
);
});
}
#[test]
fn test_to_array() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
assert_eq!(Mask::<2, T, A>::new(x, y).to_array(), [x, y]);
assert_eq!(Mask::<3, T, A>::new(x, y, z).to_array(), [x, y, z]);
assert_eq!(Mask::<4, T, A>::new(x, y, z, w).to_array(), [x, y, z, w]);
});
}
#[test]
fn test_all() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
assert_eq!(Mask::<2, T, A>::new(x, y).all(), x && y);
assert_eq!(Mask::<3, T, A>::new(x, y, z).all(), x && y && z);
assert_eq!(Mask::<4, T, A>::new(x, y, z, w).all(), x && y && z && w);
});
}
#[test]
fn test_any() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
assert_eq!(Mask::<2, T, A>::new(x, y).any(), x || y);
assert_eq!(Mask::<3, T, A>::new(x, y, z).any(), x || y || z);
assert_eq!(Mask::<4, T, A>::new(x, y, z, w).any(), x || y || z || w);
});
}
#[test]
fn test_select() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
let [a, b, c, d, e, f, g, h] = std::array::from_fn(T::as_from);
assert_eq!(
Mask::<2, T, A>::new(x, y)
.select(Vector::<2, T, A>::new(a, b), Vector::<2, T, A>::new(c, d)),
Vector::<2, T, A>::new(if x { a } else { c }, if y { b } else { d })
);
assert_eq!(
Mask::<3, T, A>::new(x, y, z).select(
Vector::<3, T, A>::new(a, b, c),
Vector::<3, T, A>::new(d, e, f)
),
Vector::<3, T, A>::new(
if x { a } else { d },
if y { b } else { e },
if z { c } else { f }
)
);
assert_eq!(
Mask::<4, T, A>::new(x, y, z, w).select(
Vector::<4, T, A>::new(a, b, c, d),
Vector::<4, T, A>::new(e, f, g, h)
),
Vector::<4, T, A>::new(
if x { a } else { e },
if y { b } else { f },
if z { c } else { g },
if w { d } else { h }
)
);
});
}
#[test]
fn test_iter() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
assert_eq!(Mask::<2, T, A>::new(x, y).iter().collect_vec(), vec![x, y]);
assert_eq!(
Mask::<3, T, A>::new(x, y, z).iter().collect_vec(),
vec![x, y, z]
);
assert_eq!(
Mask::<4, T, A>::new(x, y, z, w).iter().collect_vec(),
vec![x, y, z, w]
);
});
}
#[test]
fn test_get() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
assert_eq!(Mask::<2, T, A>::new(x, y).get(0), x);
assert_eq!(Mask::<2, T, A>::new(x, y).get(1), y);
assert_panic!(Mask::<2, T, A>::new(x, y).get(2));
assert_eq!(Mask::<3, T, A>::new(x, y, z).get(0), x);
assert_eq!(Mask::<3, T, A>::new(x, y, z).get(1), y);
assert_eq!(Mask::<3, T, A>::new(x, y, z).get(2), z);
assert_panic!(Mask::<3, T, A>::new(x, y, z).get(3));
assert_eq!(Mask::<4, T, A>::new(x, y, z, w).get(0), x);
assert_eq!(Mask::<4, T, A>::new(x, y, z, w).get(1), y);
assert_eq!(Mask::<4, T, A>::new(x, y, z, w).get(2), z);
assert_eq!(Mask::<4, T, A>::new(x, y, z, w).get(3), w);
assert_panic!(Mask::<4, T, A>::new(x, y, z, w).get(4));
});
}
#[test]
fn test_set() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
let mut mask = Mask::<2, T, A>::new(x, y);
mask.set(0, z);
assert_eq!(mask, Mask::<2, T, A>::new(z, y));
mask.set(1, w);
assert_eq!(mask, Mask::<2, T, A>::new(z, w));
assert_panic!(mask.clone().set(2, x));
let mut mask = Mask::<3, T, A>::new(x, y, z);
mask.set(0, z);
assert_eq!(mask, Mask::<3, T, A>::new(z, y, z));
mask.set(1, w);
assert_eq!(mask, Mask::<3, T, A>::new(z, w, z));
mask.set(2, x);
assert_eq!(mask, Mask::<3, T, A>::new(z, w, x));
assert_panic!(mask.clone().set(3, x));
let mut mask = Mask::<4, T, A>::new(x, y, z, w);
mask.set(0, z);
assert_eq!(mask, Mask::<4, T, A>::new(z, y, z, w));
mask.set(1, w);
assert_eq!(mask, Mask::<4, T, A>::new(z, w, z, w));
mask.set(2, x);
assert_eq!(mask, Mask::<4, T, A>::new(z, w, x, w));
mask.set(3, y);
assert_eq!(mask, Mask::<4, T, A>::new(z, w, x, y));
assert_panic!(mask.clone().set(4, x));
});
}
#[test]
fn test_to_repr() {
for_parameters!(|A, x, y, z, w| {
assert_eq!(
Mask::<2, i32, A>::new(x, y).to_repr(),
Mask::<2, u32, A>::new(x, y)
);
assert_eq!(
Mask::<3, i32, A>::new(x, y, z).to_repr(),
Mask::<3, u32, A>::new(x, y, z)
);
assert_eq!(
Mask::<4, i32, A>::new(x, y, z, w).to_repr(),
Mask::<4, u32, A>::new(x, y, z, w)
);
});
}
#[test]
fn test_into_iter() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
assert_eq!(
Mask::<2, T, A>::new(x, y).into_iter().collect_vec(),
vec![x, y]
);
assert_eq!(
Mask::<3, T, A>::new(x, y, z).into_iter().collect_vec(),
vec![x, y, z]
);
assert_eq!(
Mask::<4, T, A>::new(x, y, z, w).into_iter().collect_vec(),
vec![x, y, z, w]
);
});
}
#[test]
fn test_debug() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
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_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
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_parameters!(|T: PrimitiveNumber, A, x, y, z, w, a, b, c, d| {
assert_eq!(
Mask::<2, T, A>::new(x, y) == Mask::<2, T, A>::new(z, w),
x == z && y == w
);
assert_eq!(
Mask::<3, T, A>::new(x, y, z) == Mask::<3, T, A>::new(w, a, b),
x == w && y == a && z == b
);
assert_eq!(
Mask::<4, T, A>::new(x, y, z, w) == Mask::<4, T, A>::new(a, b, c, d),
x == a && y == b && z == c && w == d
);
});
}
#[test]
fn test_ne() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w, a, b, c, d| {
assert_eq!(
Mask::<2, T, A>::new(x, y) != Mask::<2, T, A>::new(z, w),
x != z || y != w
);
assert_eq!(
Mask::<3, T, A>::new(x, y, z) != Mask::<3, T, A>::new(w, a, b),
x != w || y != a || z != b
);
assert_eq!(
Mask::<4, T, A>::new(x, y, z, w) != Mask::<4, T, A>::new(a, b, c, d),
x != a || y != b || z != c || w != d
);
});
}
#[test]
fn test_default() {
for_parameters!(|T: PrimitiveNumber, A| {
assert_eq!(Mask::<2, T, A>::default(), Mask::splat(bool::default()));
assert_eq!(Mask::<3, T, A>::default(), Mask::splat(bool::default()));
assert_eq!(Mask::<4, T, A>::default(), Mask::splat(bool::default()));
});
}
#[test]
fn test_not() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w| {
assert_eq!(!Mask::<2, T, A>::new(x, y), Mask::<2, T, A>::new(!x, !y));
assert_eq!(
!Mask::<3, T, A>::new(x, y, z),
Mask::<3, T, A>::new(!x, !y, !z)
);
assert_eq!(
!Mask::<4, T, A>::new(x, y, z, w),
Mask::<4, T, A>::new(!x, !y, !z, !w)
);
});
}
#[test]
fn test_bitand() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w, a, b, c, d| {
assert_eq!(
Mask::<2, T, A>::new(x, y) & Mask::<2, T, A>::new(z, w),
Mask::<2, T, A>::new(x && z, y && w)
);
assert_eq!(
Mask::<3, T, A>::new(x, y, z) & Mask::<3, T, A>::new(w, a, b),
Mask::<3, T, A>::new(x && w, y && a, z && b)
);
assert_eq!(
Mask::<4, T, A>::new(x, y, z, w) & Mask::<4, T, A>::new(a, b, c, d),
Mask::<4, T, A>::new(x && a, y && b, z && c, w && d)
);
});
}
#[test]
fn test_bitor() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w, a, b, c, d| {
assert_eq!(
Mask::<2, T, A>::new(x, y) | Mask::<2, T, A>::new(z, w),
Mask::<2, T, A>::new(x || z, y || w)
);
assert_eq!(
Mask::<3, T, A>::new(x, y, z) | Mask::<3, T, A>::new(w, a, b),
Mask::<3, T, A>::new(x || w, y || a, z || b)
);
assert_eq!(
Mask::<4, T, A>::new(x, y, z, w) | Mask::<4, T, A>::new(a, b, c, d),
Mask::<4, T, A>::new(x || a, y || b, z || c, w || d)
);
});
}
#[test]
fn test_bitxor() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w, a, b, c, d| {
assert_eq!(
Mask::<2, T, A>::new(x, y) ^ Mask::<2, T, A>::new(z, w),
Mask::<2, T, A>::new(x ^ z, y ^ w)
);
assert_eq!(
Mask::<3, T, A>::new(x, y, z) ^ Mask::<3, T, A>::new(w, a, b),
Mask::<3, T, A>::new(x ^ w, y ^ a, z ^ b)
);
assert_eq!(
Mask::<4, T, A>::new(x, y, z, w) ^ Mask::<4, T, A>::new(a, b, c, d),
Mask::<4, T, A>::new(x ^ a, y ^ b, z ^ c, w ^ d)
);
});
}
#[test]
fn test_bitand_assign() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w, a, b, c, d| {
let mut mask = Mask::<2, T, A>::new(x, y);
mask &= Mask::<2, T, A>::new(z, w);
assert_eq!(mask, Mask::<2, T, A>::new(x && z, y && w));
let mut mask = Mask::<3, T, A>::new(x, y, z);
mask &= Mask::<3, T, A>::new(w, a, b);
assert_eq!(mask, Mask::<3, T, A>::new(x && w, y && a, z && b));
let mut mask = Mask::<4, T, A>::new(x, y, z, w);
mask &= Mask::<4, T, A>::new(a, b, c, d);
assert_eq!(mask, Mask::<4, T, A>::new(x && a, y && b, z && c, w && d));
});
}
#[test]
fn test_bitor_assign() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w, a, b, c, d| {
let mut mask = Mask::<2, T, A>::new(x, y);
mask |= Mask::<2, T, A>::new(z, w);
assert_eq!(mask, Mask::<2, T, A>::new(x || z, y || w));
let mut mask = Mask::<3, T, A>::new(x, y, z);
mask |= Mask::<3, T, A>::new(w, a, b);
assert_eq!(mask, Mask::<3, T, A>::new(x || w, y || a, z || b));
let mut mask = Mask::<4, T, A>::new(x, y, z, w);
mask |= Mask::<4, T, A>::new(a, b, c, d);
assert_eq!(mask, Mask::<4, T, A>::new(x || a, y || b, z || c, w || d));
});
}
#[test]
fn test_bitxor_assign() {
for_parameters!(|T: PrimitiveNumber, A, x, y, z, w, a, b, c, d| {
let mut mask = Mask::<2, T, A>::new(x, y);
mask ^= Mask::<2, T, A>::new(z, w);
assert_eq!(mask, Mask::<2, T, A>::new(x ^ z, y ^ w));
let mut mask = Mask::<3, T, A>::new(x, y, z);
mask ^= Mask::<3, T, A>::new(w, a, b);
assert_eq!(mask, Mask::<3, T, A>::new(x ^ w, y ^ a, z ^ b));
let mut mask = Mask::<4, T, A>::new(x, y, z, w);
mask ^= Mask::<4, T, A>::new(a, b, c, d);
assert_eq!(mask, Mask::<4, T, A>::new(x ^ a, y ^ b, z ^ c, w ^ d));
});
}
}