use crate::{
__internal,
Mask,
Select,
Vector,
column_major,
marker::{CastFrom, Lane, Signed, StoredVerbatim},
private,
row_major,
support::{Element, FloatElement, IntElement, MaskElement, SintElement, UintElement},
};
pub(crate) mod vector {
macro_rules! call {
(<$t:ty, $r:tt>::$f:ident $(::<$gen:ty>)? $(($($arg:expr),*))?) => {
<$t as $crate::private::SealedElement<$r, 1>>::$f $(::<$gen>)? $(($($arg),*))?
};
($w:ident(<$t:ty, $r:tt>::$f:ident $(::<$gen:ty>)? $(($($arg:expr),*))?)) => {
$w { storage: $crate::api::vector::call!(<$t, $r>::$f $(::<$gen>)? $(($($arg),*))?) }
};
(<$t:ty, $r:tt>::$f:ident $(::<$($gen:tt),+>)? $(($($arg:expr),*))?) => {
<$t as $crate::private::SealedElement<$r, 1>>::$f $(::<$($gen),+>)? $(($($arg),*))?
};
($w:ident(<$t:ty, $r:tt>::$f:ident $(::<$($gen:tt),+>)? $(($($arg:expr),*))?)) => {
$w { storage: $crate::api::vector::call!(<$t, $r>::$f $(::<$($gen),+>)? $(($($arg),*))?) }
};
}
pub(crate) use crate::Vector;
pub(crate) use call;
}
macro_rules! impl_from_array {
($t:ty, $D:expr, $array:expr, [$($d:literal),*]) => {
match $D {
$($d => {
let a = core::mem::transmute_copy::<[T; $D], [$t; $d]>(& $array);
let a = paste::paste!(crate::kernels::from_array::$t:: [<_ $d x1>])([a]);
core::mem::transmute_copy::<
<$t as private::SealedElement<$d, 1>>::Storage,
<T as private::SealedElement<$D, 1>>::Storage,
>(&a)
},)*
_ => unreachable!(),
}
}
}
impl<T: Element<D>, const D: usize> Vector<T, D> {
pub const ZERO: Self = vector::call!(Self(<T, D>::ZERO));
pub const ONE: Self = vector::call!(Self(<T, D>::ONE));
#[inline]
pub fn splat(value: T) -> Self { vector::call!(Self(<T, D>::filled(value))) }
#[inline(always)]
pub(crate) fn filled(value: T) -> Self { vector::call!(Self(<T, D>::filled(value))) }
#[inline]
pub const fn from_array(array: [T; D]) -> Self {
let mut out =
core::mem::MaybeUninit::<<T as private::SealedElement<D, 1>>::Storage>::uninit();
let storage = unsafe {
match <T as private::Sealed>::TYPE {
private::Type::F32 => impl_from_array!(f32, D, &array, [1, 2, 3, 4]),
private::Type::F64 => impl_from_array!(f64, D, &array, [1, 2, 3, 4]),
private::Type::I32 => impl_from_array!(i32, D, &array, [1, 2, 3, 4]),
private::Type::I64 => impl_from_array!(i64, D, &array, [1, 2, 3, 4]),
private::Type::U32 => impl_from_array!(u32, D, &array, [1, 2, 3, 4]),
private::Type::U64 => impl_from_array!(u64, D, &array, [1, 2, 3, 4]),
}
};
Self { storage: *out.write(storage) }
}
#[inline]
pub fn to_array(self) -> [T; D] { vector::call!(<T, D>::to_array(self.storage))[0] }
#[inline]
pub fn cast<U: Element<D> + CastFrom<T>>(self) -> Vector<U, D> {
vector::call!(Vector(<U, D>::cast_from::<T>(self.storage)))
}
}
impl<T: FloatElement<D>, const D: usize> Vector<T, D> {
#[inline]
pub fn dot(self, rhs: Self) -> T { vector::call!(<T, D>::dot(self.storage, rhs.storage)) }
#[inline]
pub fn norm(self) -> T { <T as private::Sealed>::sqrt(self.norm_squared()) }
#[inline]
pub fn norm_squared(self) -> T { self.dot(self) }
#[inline]
pub fn distance(self, rhs: Self) -> T {
<T as private::Sealed>::sqrt(self.distance_squared(rhs))
}
#[inline]
pub fn distance_squared(self, rhs: Self) -> T { (self - rhs).norm_squared() }
#[inline]
pub fn normalize(self) -> Self { self / self.norm() }
#[inline]
pub fn floor(self) -> Self { vector::call!(Self(<T, D>::floor(self.storage))) }
#[inline]
pub fn ceil(self) -> Self { vector::call!(Self(<T, D>::ceil(self.storage))) }
#[inline]
pub fn round(self) -> Self { vector::call!(Self(<T, D>::round(self.storage))) }
#[inline]
pub fn round_ties_even(self) -> Self {
vector::call!(Self(<T, D>::round_ties_even(self.storage)))
}
#[inline]
pub fn trunc(self) -> Self { vector::call!(Self(<T, D>::trunc(self.storage))) }
#[inline]
pub fn fract(self) -> Self { vector::call!(Self(<T, D>::fract(self.storage))) }
#[inline]
pub fn sqrt(self) -> Self { vector::call!(Self(<T, D>::sqrt(self.storage))) }
#[inline]
pub fn recip(self) -> Self { Self::ONE / self }
#[inline]
pub fn from_bits(v: Vector<T::Bits, D>) -> Self {
vector::call!(Self(<T, D>::from_bits(v.storage)))
}
#[inline]
pub fn to_bits(self) -> Vector<T::Bits, D> {
vector::call!(Vector(<T, D>::to_bits(self.storage)))
}
}
impl<T: Signed + Element<D>, const D: usize> Vector<T, D> {
#[inline]
pub fn abs(self) -> Self { vector::call!(Self(<T, D>::abs(self.storage))) }
}
impl<T: Element<D>, const D: usize> Vector<T, D>
where
__internal::Dimension<D>: __internal::AtLeast<1>,
{
pub const POS_X: Self = vector::call!(Self(<T, D>::POS_X));
}
impl<T: Signed + Element<D>, const D: usize> Vector<T, D>
where
__internal::Dimension<D>: __internal::AtLeast<1>,
{
pub const NEG_X: Self = vector::call!(Self(<T, D>::NEG_X));
}
impl<T: Element<D>, const D: usize> Vector<T, D>
where
__internal::Dimension<D>: __internal::AtLeast<2>,
{
pub const POS_Y: Self = vector::call!(Self(<T, D>::POS_Y));
}
impl<T: Signed + Element<D>, const D: usize> Vector<T, D>
where
__internal::Dimension<D>: __internal::AtLeast<2>,
{
pub const NEG_Y: Self = vector::call!(Self(<T, D>::NEG_Y));
}
impl<T: Element<D>, const D: usize> Vector<T, D>
where
__internal::Dimension<D>: __internal::AtLeast<3>,
{
pub const POS_Z: Self = vector::call!(Self(<T, D>::POS_Z));
}
impl<T: Signed + Element<D>, const D: usize> Vector<T, D>
where
__internal::Dimension<D>: __internal::AtLeast<3>,
{
pub const NEG_Z: Self = vector::call!(Self(<T, D>::NEG_Z));
}
impl<T: Element<D>, const D: usize> Vector<T, D>
where
__internal::Dimension<D>: __internal::AtLeast<4>,
{
pub const POS_W: Self = vector::call!(Self(<T, D>::POS_W));
}
impl<T: Signed + Element<D>, const D: usize> Vector<T, D>
where
__internal::Dimension<D>: __internal::AtLeast<4>,
{
pub const NEG_W: Self = vector::call!(Self(<T, D>::NEG_W));
}
impl<T: IntElement<D>, const D: usize> Vector<T, D> {
#[inline]
pub fn abs_diff(self, other: Self) -> Vector<T::Unsigned, D> {
use crate::Select;
let left = vector::call!(Vector(<T, D>::cast_unsigned(self.storage)));
let right = vector::call!(Vector(<T, D>::cast_unsigned(other.storage)));
let a = left - right;
let b = right - left;
self.each_lt(other).select(b, a)
}
}
impl<T: SintElement<D>, const D: usize> Vector<T, D> {
#[inline]
pub fn cast_unsigned(self) -> Vector<T::Unsigned, D> {
vector::call!(Vector(<T, D>::cast_unsigned(self.storage)))
}
}
impl<T: UintElement<D>, const D: usize> Vector<T, D> {
#[inline]
pub fn cast_signed(self) -> Vector<T::Signed, D> {
vector::call!(Vector(<T, D>::cast_signed(self.storage)))
}
}
macro_rules! impl_matrix_from_array {
($t:ty, $M:expr, $N:expr, $array:expr, $ms:tt, [$($n:literal),*]) => {
match $N {
$($n => impl_matrix_from_array!(@m $t, $M, $N, $array, $n, $ms),)*
_ => unreachable!(),
}
};
(@m $t:ty, $M:expr, $N:expr, $array:expr, $n:literal, [$($m:literal),*]) => {
match $M {
$($m => {
let a = core::mem::transmute_copy::<
[[T; $M]; $N],
[[$t; $m]; $n],
>($array);
let a = paste::paste!(crate::kernels::from_array::$t:: [<_ $m x $n>])(a);
core::mem::transmute_copy::<
<$t as private::SealedElement<$m, $n>>::Storage,
<T as private::SealedElement<$M, $N>>::Storage,
>(&a)
},)*
_ => unreachable!(),
}
};
}
impl<T: Element<R, C>, const R: usize, const C: usize> row_major::Matrix<T, R, C> {
pub const ZERO: Self = row_major::call!(Self(<T, R, C>::ZERO));
pub const ONE: Self = row_major::call!(Self(<T, R, C>::ONE));
#[inline]
pub fn filled(value: T) -> row_major::Matrix<T, R, C> {
row_major::call!(Self(<T, R, C>::filled(value)))
}
#[inline]
pub const fn from_rows(rows: [[T; C]; R]) -> Self {
let mut out =
core::mem::MaybeUninit::<<T as private::SealedElement<C, R>>::Storage>::uninit();
let storage = unsafe {
match <T as private::Sealed>::TYPE {
private::Type::F32 => {
impl_matrix_from_array!(f32, C, R, &rows, [1, 2, 3, 4], [1, 2, 3, 4])
}
private::Type::F64 => {
impl_matrix_from_array!(f64, C, R, &rows, [1, 2, 3, 4], [1, 2, 3, 4])
}
private::Type::I32 => {
impl_matrix_from_array!(i32, C, R, &rows, [1, 2, 3, 4], [1, 2, 3, 4])
}
private::Type::I64 => {
impl_matrix_from_array!(i64, C, R, &rows, [1, 2, 3, 4], [1, 2, 3, 4])
}
private::Type::U32 => {
impl_matrix_from_array!(u32, C, R, &rows, [1, 2, 3, 4], [1, 2, 3, 4])
}
private::Type::U64 => {
impl_matrix_from_array!(u64, C, R, &rows, [1, 2, 3, 4], [1, 2, 3, 4])
}
}
};
Self { storage: *out.write(storage) }
}
#[inline]
pub fn from_row_vecs(rows: [Vector<T, C>; R]) -> Self {
row_major::call!(Self(<T, R, C>::from_vecs(rows)))
}
#[inline]
pub fn to_rows(self) -> [[T; C]; R] { row_major::call!(<T, R, C>::to_array(self.storage)) }
#[inline]
pub fn to_row_vecs(self) -> [Vector<T, C>; R] { self.to_rows().map(Vector::from) }
#[inline]
pub fn transpose(self) -> row_major::Matrix<T, C, R> {
use row_major::Matrix;
row_major::call!(Matrix(<T, R, C>::transpose(self.storage)))
}
#[inline]
pub const fn to_column_major_transposed(self) -> column_major::Matrix<T, C, R> {
column_major::Matrix { storage: self.storage }
}
#[inline]
pub fn cast<U: Element<R, C> + CastFrom<T>>(self) -> row_major::Matrix<U, R, C> {
use row_major::Matrix;
row_major::call!(Matrix(<U, R, C>::cast_from::<T>(self.storage)))
}
}
impl<T: Element<R, C>, const R: usize, const C: usize> column_major::Matrix<T, R, C> {
pub const ZERO: Self = column_major::call!(Self(<T, R, C>::ZERO));
pub const ONE: Self = column_major::call!(Self(<T, R, C>::ONE));
#[inline]
pub fn filled(value: T) -> column_major::Matrix<T, R, C> {
column_major::call!(Self(<T, R, C>::filled(value)))
}
#[inline]
pub const fn from_columns(columns: [[T; R]; C]) -> Self {
let mut out =
core::mem::MaybeUninit::<<T as private::SealedElement<R, C>>::Storage>::uninit();
let storage = unsafe {
match <T as private::Sealed>::TYPE {
private::Type::F32 => {
impl_matrix_from_array!(f32, R, C, &columns, [1, 2, 3, 4], [1, 2, 3, 4])
}
private::Type::F64 => {
impl_matrix_from_array!(f64, R, C, &columns, [1, 2, 3, 4], [1, 2, 3, 4])
}
private::Type::I32 => {
impl_matrix_from_array!(i32, R, C, &columns, [1, 2, 3, 4], [1, 2, 3, 4])
}
private::Type::I64 => {
impl_matrix_from_array!(i64, R, C, &columns, [1, 2, 3, 4], [1, 2, 3, 4])
}
private::Type::U32 => {
impl_matrix_from_array!(u32, R, C, &columns, [1, 2, 3, 4], [1, 2, 3, 4])
}
private::Type::U64 => {
impl_matrix_from_array!(u64, R, C, &columns, [1, 2, 3, 4], [1, 2, 3, 4])
}
}
};
Self { storage: *out.write(storage) }
}
#[inline]
pub fn from_column_vecs(columns: [Vector<T, R>; C]) -> Self {
column_major::call!(Self(<T, R, C>::from_vecs(columns)))
}
#[inline]
pub fn to_columns(self) -> [[T; R]; C] {
column_major::call!(<T, R, C>::to_array(self.storage))
}
#[inline]
pub fn to_column_vecs(self) -> [Vector<T, R>; C] { self.to_columns().map(Vector::from) }
#[inline]
pub fn transpose(self) -> column_major::Matrix<T, C, R> {
use column_major::Matrix;
column_major::call!(Matrix(<T, R, C>::transpose(self.storage)))
}
#[inline]
pub const fn to_row_major_transposed(self) -> row_major::Matrix<T, C, R> {
row_major::Matrix { storage: self.storage }
}
#[inline]
pub fn cast<U: Element<R, C> + CastFrom<T>>(self) -> column_major::Matrix<U, R, C> {
use column_major::Matrix;
column_major::call!(Matrix(<U, R, C>::cast_from::<T>(self.storage)))
}
}
macro_rules! if_match {
(($_:tt) { $($then:tt)* } else { $($else:tt)* }) => { $($then)* };
(() { $($then:tt)* } else { $($else:tt)* }) => { $($else)* };
}
macro_rules! impl_binop {
(
docs: [$doc:literal, $assign_doc:literal],
$mod:tt::$Tensor:tt,
$(any:$T:tt,)? // self_tensor
$(spec:$t:tt,)? // self_scalar
$(rhs_tensor:$rhs_tensor:tt,)?
$(rhs_scalar:$rhs_scalar:tt,)?
[$($N:tt),+],
$trait:ident::$method:ident
$(, $trait_assign:ident::$method_assign:ident)?
) => {
impl<$($T,)? $(const $N: usize),+> core::ops::$trait<
if_match!(($($rhs_tensor)?) { $mod::$Tensor<$($T)? $($t)?, $($N),+> } else { $($T)? })
> for if_match!(($($T)?) { $mod::$Tensor<$($T)?, $($N),+> } else { $($t)? } )
where $($T)? $($t)?: Element<$($N),+> $(+ core::ops::$trait<Output = $T>)?
{
type Output = $mod::$Tensor<$($T)? $($t)?, $($N),+>;
#[doc = $doc]
#[inline]
fn $method(
self,
rhs: if_match!(($($rhs_tensor)?) { $mod::$Tensor<$($T)? $($t)?, $($N),+> } else { $($T)? } ),
) -> Self::Output {
use $mod::$Tensor;
let lhs = if_match!(($($T)?) { self.storage } else { $Tensor::filled(self).storage });
let rhs = if_match!(($($rhs_tensor)?) { rhs.storage } else { $Tensor::filled(rhs).storage });
$mod::call!($Tensor(<$($T)? $($t)?, $($N),+>::$method(lhs, rhs)))
}
}
if_match!{ ($($trait_assign)?) {
impl<$($T,)? $(const $N: usize),+> core::ops::$($trait_assign)?<
if_match!(($($rhs_tensor)?) { $mod::$Tensor<$($T)? $($t)?, $($N),+> } else { $($T)? })
> for $mod::$Tensor<$($T)?, $($N),+>
where $($T)? $($t)?: Element<$($N),+> $(+ core::ops::$trait<Output = $T>)?
{
#[doc = $assign_doc]
#[inline]
fn $($method_assign)?(
&mut self,
rhs: if_match!(($($rhs_tensor)?) { $mod::$Tensor<$($T)? $($t)?, $($N),+> } else { $($T)? }),
) {
*self = core::ops::$trait::$method(*self, rhs);
}
}
} else {}}
};
}
macro_rules! impl_binop_all {
(@a [$docs:tt, $trait:tt::$method:tt, $trait_assign:tt::$method_assign:tt, not_matrix]) => {
impl_binop!(docs: $docs, vector::Vector, any:T, rhs_tensor:_, [D], $trait::$method, $trait_assign::$method_assign);
impl_binop!(docs: $docs, vector::Vector, any:T, rhs_scalar:_, [D], $trait::$method, $trait_assign::$method_assign);
impl_binop!(docs: $docs, row_major::Matrix, any:T, rhs_scalar:_, [R, C], $trait::$method, $trait_assign::$method_assign);
impl_binop!(docs: $docs, column_major::Matrix, any:T, rhs_scalar:_, [R, C], $trait::$method, $trait_assign::$method_assign);
};
(@a [$docs:tt, $trait:tt::$method:tt, $trait_assign:tt::$method_assign:tt, vector_only]) => {
impl_binop!(docs: $docs, vector::Vector, any:T, rhs_tensor:_, [D], $trait::$method, $trait_assign::$method_assign);
impl_binop!(docs: $docs, vector::Vector, any:T, rhs_scalar:_, [D], $trait::$method, $trait_assign::$method_assign);
};
(@a [$docs:tt, $trait:tt::$method:tt, $trait_assign:tt::$method_assign:tt, vector_and_mask]) => {
impl_binop!(docs: $docs, vector::Vector, any:T, rhs_tensor:_, [D], $trait::$method, $trait_assign::$method_assign);
impl_binop!(docs: $docs, vector::Vector, any:T, rhs_scalar:_, [D], $trait::$method, $trait_assign::$method_assign);
impl_binop!(docs: $docs, vector::Vector, any:T, rhs_scalar:_, [D], $trait::$method, $trait_assign::$method_assign);
impl_binop!(docs: $docs, vector::Vector, any:T, rhs_scalar:_, [D], $trait::$method, $trait_assign::$method_assign);
};
(@a [$docs:tt, $trait:tt::$method:tt, $trait_assign:tt::$method_assign:tt]) => {
impl_binop!(docs: $docs, vector::Vector, any:T, rhs_tensor:_, [D], $trait::$method, $trait_assign::$method_assign);
impl_binop!(docs: $docs, vector::Vector, any:T, rhs_scalar:_, [D], $trait::$method, $trait_assign::$method_assign);
impl_binop!(docs: $docs, row_major::Matrix, any:T, rhs_tensor:_, [R, C], $trait::$method, $trait_assign::$method_assign);
impl_binop!(docs: $docs, row_major::Matrix, any:T, rhs_scalar:_, [R, C], $trait::$method, $trait_assign::$method_assign);
impl_binop!(docs: $docs, column_major::Matrix, any:T, rhs_tensor:_, [R, C], $trait::$method, $trait_assign::$method_assign);
impl_binop!(docs: $docs, column_major::Matrix, any:T, rhs_scalar:_, [R, C], $trait::$method, $trait_assign::$method_assign);
};
(@b [$($scalar:tt),+], [$docs:tt, $trait:tt::$method:tt], vector_only) => {
$(
impl_binop!(docs: $docs, vector::Vector,spec:$scalar,rhs_tensor:_,[D],$trait::$method);
)+
};
(@b [$($scalar:tt),+], [$docs:tt, $trait:tt::$method:tt] $(,$option:tt)?) => {
$(
impl_binop!(docs: $docs, vector::Vector,spec:$scalar,rhs_tensor:_,[D],$trait::$method);
impl_binop!(docs: $docs, row_major::Matrix,spec:$scalar,rhs_tensor:_,[R, C],$trait::$method);
impl_binop!(docs: $docs, column_major::Matrix,spec:$scalar,rhs_tensor:_,[R, C],$trait::$method);
)+
};
(arithmetic, [$([$generic_docs:tt, $float_docs:tt, $integer_docs:tt, $trait:tt::$method:tt, $trait_assign:tt::$method_assign:tt $(, $option:tt)?],)+]) => {
$(
impl_binop_all!(@a [$generic_docs, $trait::$method, $trait_assign::$method_assign $(, $option)?]);
impl_binop_all!(@b [f32, f64], [$float_docs, $trait::$method] $(, $option)?);
impl_binop_all!(@b [i32, u32, i64, u64], [$integer_docs, $trait::$method] $(, $option)?);
)+
};
($scalar:tt, [$([$docs:tt, $trait:tt::$method:tt, $trait_assign:tt::$method_assign:tt $(, $option:tt)?],)+]) => {
$(
impl_binop_all!(@a [$docs, $trait::$method, $trait_assign::$method_assign $(, $option)?]);
impl_binop_all!(@b $scalar, [$docs, $trait::$method] $(, $option)?);
)+
};
}
impl_binop_all!(arithmetic, [
[
[
"Performs component-wise addition.\n\nFor integer element types, the result wraps on overflow.",
"Performs component-wise addition assignment.\n\nFor integer element types, the result wraps on overflow."
],
["Performs component-wise addition.", "Performs component-wise addition assignment."],
[
"Performs component-wise addition.\n\nThe result wraps on overflow.",
"Performs component-wise addition assignment.\n\nThe result wraps on overflow."
],
Add::add,
AddAssign::add_assign
],
[
[
"Performs component-wise subtraction.\n\nFor integer element types, the result wraps on overflow.",
"Performs component-wise subtraction assignment.\n\nFor integer element types, the result wraps on overflow."
],
["Performs component-wise subtraction.", "Performs component-wise subtraction assignment."],
[
"Performs component-wise subtraction.\n\nThe result wraps on overflow.",
"Performs component-wise subtraction assignment.\n\nThe result wraps on overflow."
],
Sub::sub,
SubAssign::sub_assign
],
[
[
"Performs component-wise multiplication.\n\nFor integer element types, the result wraps on overflow.",
"Performs component-wise multiplication assignment.\n\nFor integer element types, the result wraps on overflow."
],
[
"Performs component-wise multiplication.",
"Performs component-wise multiplication assignment."
],
[
"Performs component-wise multiplication.\n\nThe result wraps on overflow.",
"Performs component-wise multiplication assignment.\n\nThe result wraps on overflow."
],
Mul::mul,
MulAssign::mul_assign,
not_matrix
],
[
[
"Performs component-wise division.\n\nInteger division rounds toward zero and wraps on overflow.\n\n# Panics\n\nFor integer element types, panics if any active divisor element is zero.",
"Performs component-wise division assignment.\n\nInteger division rounds toward zero and wraps on overflow.\n\n# Panics\n\nFor integer element types, panics if any active divisor element is zero."
],
["Performs component-wise division.", "Performs component-wise division assignment."],
[
"Performs component-wise division.\n\nDivision rounds toward zero and wraps on overflow.\n\n# Panics\n\nPanics if any active divisor element is zero.",
"Performs component-wise division assignment.\n\nDivision rounds toward zero and wraps on overflow.\n\n# Panics\n\nPanics if any active divisor element is zero."
],
Div::div,
DivAssign::div_assign,
not_matrix
],
[
[
"Performs component-wise remainder.\n\nFor integer element types, the result uses wrapping remainder semantics.\n\n# Panics\n\nFor integer element types, panics if any active divisor element is zero.",
"Performs component-wise remainder assignment.\n\nFor integer element types, the result uses wrapping remainder semantics.\n\n# Panics\n\nFor integer element types, panics if any active divisor element is zero."
],
["Performs component-wise remainder.", "Performs component-wise remainder assignment."],
[
"Performs component-wise remainder.\n\nThe result uses wrapping integer remainder semantics.\n\n# Panics\n\nPanics if any active divisor element is zero.",
"Performs component-wise remainder assignment.\n\nThe result uses wrapping integer remainder semantics.\n\n# Panics\n\nPanics if any active divisor element is zero."
],
Rem::rem,
RemAssign::rem_assign,
vector_only
],
]);
impl_binop_all!([i32, u32, i64, u64], [
[
["Performs component-wise bitwise AND.", "Performs component-wise bitwise AND assignment."],
BitAnd::bitand,
BitAndAssign::bitand_assign,
vector_only
],
[
["Performs component-wise bitwise OR.", "Performs component-wise bitwise OR assignment."],
BitOr::bitor,
BitOrAssign::bitor_assign,
vector_only
],
[
["Performs component-wise bitwise XOR.", "Performs component-wise bitwise XOR assignment."],
BitXor::bitxor,
BitXorAssign::bitxor_assign,
vector_only
],
[
["Performs component-wise left shift.", "Performs component-wise left-shift assignment."],
Shl::shl,
ShlAssign::shl_assign,
vector_only
],
[
["Performs component-wise right shift.", "Performs component-wise right-shift assignment."],
Shr::shr,
ShrAssign::shr_assign,
vector_only
],
]);
impl<T: core::ops::Neg + Element<R, C>, const R: usize, const C: usize> core::ops::Neg
for row_major::Matrix<T, R, C>
{
type Output = Self;
#[inline]
fn neg(self) -> Self::Output { row_major::call!(Self(<T, R, C>::neg(self.storage))) }
}
impl<T: core::ops::Neg + Element<R, C>, const R: usize, const C: usize> core::ops::Neg
for column_major::Matrix<T, R, C>
{
type Output = Self;
#[inline]
fn neg(self) -> Self::Output { column_major::call!(Self(<T, R, C>::neg(self.storage))) }
}
impl<T: core::ops::Neg + Element<D>, const D: usize> core::ops::Neg for Vector<T, D> {
type Output = Self;
#[inline]
fn neg(self) -> Self::Output { vector::call!(Self(<T, D>::neg(self.storage))) }
}
impl<T: core::ops::Not + Element<D>, const D: usize> core::ops::Not for Vector<T, D> {
type Output = Self;
#[inline]
fn not(self) -> Self::Output { vector::call!(Self(<T, D>::not(self.storage))) }
}
impl<T: MaskElement<D>, const D: usize> core::ops::Not for Mask<T, D> {
type Output = Self;
#[inline]
fn not(self) -> Self::Output { vector::call!(Self(<T, D>::mask_not(self.storage))) }
}
macro_rules! impl_mask_binop {
([$([$trait:tt::$method:tt, $trait_assign:tt::$method_assign:tt, $f:tt],)+]) => {
$(
impl<T: MaskElement<D>, const D: usize> core::ops::$trait for Mask<T, D> {
type Output = Self;
#[inline]
fn $method(self, rhs: Self) -> Self::Output {
vector::call!(Self(<T, D>::$f(self.storage, rhs.storage)))
}
}
impl<T: MaskElement<D>, const D: usize> core::ops::$trait_assign for Mask<T, D> {
#[inline]
fn $method_assign(&mut self, rhs: Self) {
*self = <Self as core::ops::$trait>::$method(*self, rhs)
}
}
)+
};
}
impl_mask_binop! {
[
[BitAnd::bitand, BitAndAssign::bitand_assign, mask_bitand],
[BitOr::bitor, BitOrAssign::bitor_assign, mask_bitor],
[BitXor::bitxor, BitXorAssign::bitxor_assign, mask_bitxor],
]
}
impl<T: row_major::MatrixProduct<N, N, N>, const N: usize> core::iter::Product
for row_major::Matrix<T, N, N>
{
#[inline]
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
let mut iter = iter.into_iter();
if let Some(first) = iter.next() {
iter.fold(
first,
#[inline(always)]
|acc, x| acc * x,
)
} else {
Self::IDENTITY
}
}
}
impl<T: column_major::MatrixProduct<N, N, N>, const N: usize> core::iter::Product
for column_major::Matrix<T, N, N>
{
#[inline]
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
let mut iter = iter.into_iter();
if let Some(first) = iter.next() {
iter.fold(
first,
#[inline(always)]
|acc, x| acc * x,
)
} else {
Self::IDENTITY
}
}
}
impl<T: Element<D> + core::ops::Mul<Output = T>, const D: usize> core::iter::Product
for Vector<T, D>
{
#[inline]
fn product<I: Iterator<Item = Self>>(iter: I) -> Self {
let mut iter = iter.into_iter();
if let Some(first) = iter.next() {
iter.fold(
first,
#[inline(always)]
|acc, x| acc * x,
)
} else {
Self::ONE
}
}
}
impl<T: Element<R, C> + core::ops::Add<Output = T>, const R: usize, const C: usize> core::iter::Sum
for row_major::Matrix<T, R, C>
{
#[inline]
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
let mut iter = iter.into_iter();
if let Some(first) = iter.next() {
iter.fold(
first,
#[inline(always)]
|acc, x| acc + x,
)
} else {
Self::ZERO
}
}
}
impl<T: Element<R, C> + core::ops::Add<Output = T>, const R: usize, const C: usize> core::iter::Sum
for column_major::Matrix<T, R, C>
{
#[inline]
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
let mut iter = iter.into_iter();
if let Some(first) = iter.next() {
iter.fold(
first,
#[inline(always)]
|acc, x| acc + x,
)
} else {
Self::ZERO
}
}
}
impl<T: Element<D> + core::ops::Add<Output = T>, const D: usize> core::iter::Sum for Vector<T, D> {
#[inline]
fn sum<I: Iterator<Item = Self>>(iter: I) -> Self {
let mut iter = iter.into_iter();
if let Some(first) = iter.next() {
iter.fold(
first,
#[inline(always)]
|acc, x| acc + x,
)
} else {
Self::ZERO
}
}
}
impl<T: Element<R, C>, const R: usize, const C: usize> Default for row_major::Matrix<T, R, C> {
#[inline]
fn default() -> Self { Self::ZERO }
}
impl<T: Element<R, C>, const R: usize, const C: usize> Default for column_major::Matrix<T, R, C> {
#[inline]
fn default() -> Self { Self::ZERO }
}
impl<T: Element<D>, const D: usize> Default for Vector<T, D> {
#[inline]
fn default() -> Self { Self::ZERO }
}
impl<T: MaskElement<D>, const D: usize> Default for Mask<T, D> {
#[inline]
fn default() -> Self { Self::splat(false) }
}
struct CompactRow<'a, T>(&'a [T]);
impl<T: core::fmt::Debug> core::fmt::Debug for CompactRow<'_, T> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("[")?;
for (index, value) in self.0.iter().enumerate() {
if index != 0 {
f.write_str(", ")?;
}
core::fmt::Debug::fmt(value, f)?;
}
f.write_str("]")
}
}
impl<T: core::fmt::Debug + Element<R, C>, const R: usize, const C: usize> core::fmt::Debug
for row_major::Matrix<T, R, C>
{
#[allow(clippy::missing_inline_in_public_items)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let rows = self.to_rows();
f.debug_list().entries(rows.iter().map(|row| CompactRow(row.as_slice()))).finish()
}
}
impl<T: core::fmt::Debug + Element<R, C>, const R: usize, const C: usize> core::fmt::Debug
for column_major::Matrix<T, R, C>
{
#[allow(clippy::missing_inline_in_public_items)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let columns = self.to_columns();
f.debug_list().entries(columns.iter().map(|column| CompactRow(column.as_slice()))).finish()
}
}
impl<T: core::fmt::Debug + Element<D>, const D: usize> core::fmt::Debug for Vector<T, D> {
#[allow(clippy::missing_inline_in_public_items)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let array = self.to_array();
core::fmt::Debug::fmt(&CompactRow(array.as_slice()), f)
}
}
impl<T: MaskElement<D>, const D: usize> core::fmt::Debug for Mask<T, D> {
#[allow(clippy::missing_inline_in_public_items)]
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
let array = self.to_array();
core::fmt::Debug::fmt(&CompactRow(array.as_slice()), f)
}
}
#[allow(clippy::partialeq_ne_impl)] impl<T: PartialEq + Element<R, C>, const R: usize, const C: usize> PartialEq
for row_major::Matrix<T, R, C>
{
#[inline]
fn eq(&self, other: &Self) -> bool {
row_major::call!(<T, R, C>::eq(self.storage, other.storage))
}
#[inline]
fn ne(&self, other: &Self) -> bool {
row_major::call!(<T, R, C>::ne(self.storage, other.storage))
}
}
#[allow(clippy::partialeq_ne_impl)]
impl<T: PartialEq + Element<R, C>, const R: usize, const C: usize> PartialEq
for column_major::Matrix<T, R, C>
{
#[inline]
fn eq(&self, other: &Self) -> bool {
column_major::call!(<T, R, C>::eq(self.storage, other.storage))
}
#[inline]
fn ne(&self, other: &Self) -> bool {
column_major::call!(<T, R, C>::ne(self.storage, other.storage))
}
}
#[allow(clippy::partialeq_ne_impl)] impl<T: PartialEq + Element<D>, const D: usize> PartialEq for Vector<T, D> {
#[inline]
fn eq(&self, other: &Self) -> bool { vector::call!(<T, D>::eq(self.storage, other.storage)) }
#[inline]
fn ne(&self, other: &Self) -> bool { vector::call!(<T, D>::ne(self.storage, other.storage)) }
}
impl<T: Eq + Element<R, C>, const R: usize, const C: usize> Eq for row_major::Matrix<T, R, C> {}
impl<T: Eq + Element<R, C>, const R: usize, const C: usize> Eq for column_major::Matrix<T, R, C> {}
impl<T: Eq + Element<D>, const D: usize> Eq for Vector<T, D> {}
impl<T: PartialEq + Element<D>, const D: usize> Vector<T, D> {
#[inline]
pub fn each_eq(self, rhs: Self) -> Mask<<T as Lane>::Mask, D> {
vector::call!(Mask(<T, D>::each_eq(self.storage, rhs.storage)))
}
#[inline]
pub fn each_ne(self, rhs: Self) -> Mask<<T as Lane>::Mask, D> {
vector::call!(Mask(<T, D>::each_ne(self.storage, rhs.storage)))
}
}
impl<T: PartialOrd + Element<D>, const D: usize> Vector<T, D> {
#[inline]
pub fn each_lt(self, rhs: Self) -> Mask<<T as Lane>::Mask, D> {
vector::call!(Mask(<T, D>::each_lt(self.storage, rhs.storage)))
}
#[inline]
pub fn each_le(self, rhs: Self) -> Mask<<T as Lane>::Mask, D> {
vector::call!(Mask(<T, D>::each_le(self.storage, rhs.storage)))
}
#[inline]
pub fn each_gt(self, rhs: Self) -> Mask<<T as Lane>::Mask, D> {
vector::call!(Mask(<T, D>::each_gt(self.storage, rhs.storage)))
}
#[inline]
pub fn each_ge(self, rhs: Self) -> Mask<<T as Lane>::Mask, D> {
vector::call!(Mask(<T, D>::each_ge(self.storage, rhs.storage)))
}
}
impl<T: Ord + Element<D>, const D: usize> crate::EachOrd for Vector<T, D> {
#[inline]
fn each_max(self, rhs: Self) -> Self {
vector::call!(Self(<T, D>::each_max(self.storage, rhs.storage)))
}
#[inline]
fn each_min(self, rhs: Self) -> Self {
vector::call!(Self(<T, D>::each_min(self.storage, rhs.storage)))
}
#[inline]
fn each_clamp(self, min: Self, max: Self) -> Self {
vector::call!(Self(<T, D>::each_clamp::<private::VectorFmt>(self.storage, min.storage, max.storage)))
}
}
impl<T: FloatElement<D>, const D: usize> Vector<T, D> {
#[inline]
pub fn each_max(self, rhs: Self) -> Self {
vector::call!(Self(<T, D>::each_max(self.storage, rhs.storage)))
}
#[inline]
pub fn each_min(self, rhs: Self) -> Self {
vector::call!(Self(<T, D>::each_min(self.storage, rhs.storage)))
}
#[inline]
pub fn each_clamp(self, min: Self, max: Self) -> Self {
vector::call!(Self(<T, D>::each_clamp::<private::VectorFmt>(self.storage, min.storage, max.storage)))
}
}
impl<T: Element<R, C>, const R: usize, const C: usize> Clone for row_major::Matrix<T, R, C> {
#[inline]
fn clone(&self) -> Self { *self }
}
impl<T: Element<R, C>, const R: usize, const C: usize> Clone for column_major::Matrix<T, R, C> {
#[inline]
fn clone(&self) -> Self { *self }
}
impl<T: Element<D>, const D: usize> Clone for Vector<T, D> {
#[inline]
fn clone(&self) -> Self { *self }
}
impl<T: MaskElement<D>, const D: usize> Clone for Mask<T, D> {
#[inline]
fn clone(&self) -> Self { *self }
}
impl<T: Element<R, C>, const R: usize, const C: usize> Copy for row_major::Matrix<T, R, C> {}
impl<T: Element<R, C>, const R: usize, const C: usize> Copy for column_major::Matrix<T, R, C> {}
impl<T: Element<D>, const D: usize> Copy for Vector<T, D> {}
impl<T: MaskElement<D>, const D: usize> Copy for Mask<T, D> {}
impl<T: Element<D> + StoredVerbatim, const D: usize> Vector<T, D> {
#[inline]
pub fn as_array(&self) -> &[T; D] { vector::call!(<T, D>::as_array_first(&self.storage)) }
#[inline]
pub fn as_mut_array(&mut self) -> &mut [T; D] {
vector::call!(<T, D>::as_mut_array_first(&mut self.storage))
}
}
impl<T: Element<R, C>, const R: usize, const C: usize> From<[[T; C]; R]>
for row_major::Matrix<T, R, C>
{
#[inline]
fn from(value: [[T; C]; R]) -> Self { row_major::call!(Self(<T, R, C>::from_array(value))) }
}
impl<T: Element<R, C>, const R: usize, const C: usize> From<row_major::Matrix<T, R, C>>
for [[T; C]; R]
{
#[inline]
fn from(value: row_major::Matrix<T, R, C>) -> Self {
row_major::call!(<T, R, C>::to_array(value.storage))
}
}
impl<T: Element<R, C>, const R: usize, const C: usize> From<[[T; R]; C]>
for column_major::Matrix<T, R, C>
{
#[inline]
fn from(value: [[T; R]; C]) -> Self { column_major::call!(Self(<T, R, C>::from_array(value))) }
}
impl<T: Element<R, C>, const R: usize, const C: usize> From<column_major::Matrix<T, R, C>>
for [[T; R]; C]
{
#[inline]
fn from(value: column_major::Matrix<T, R, C>) -> Self {
column_major::call!(<T, R, C>::to_array(value.storage))
}
}
impl<T: Element<D>, const D: usize> From<[T; D]> for Vector<T, D> {
#[inline]
fn from(value: [T; D]) -> Self { vector::call!(Self(<T, D>::from_array([value]))) }
}
impl<T: Element<D>, const D: usize> From<Vector<T, D>> for [T; D] {
#[inline]
fn from(value: Vector<T, D>) -> Self { value.to_array() }
}
impl<T: MaskElement<D>, const D: usize> From<[bool; D]> for Mask<T, D> {
#[inline]
fn from(value: [bool; D]) -> Self { vector::call!(Self(<T, D>::from_bool_array([value]))) }
}
impl<T: Element<2> + StoredVerbatim> core::ops::Deref for Vector<T, 2> {
type Target = private::XY<T>;
#[inline]
fn deref(&self) -> &Self::Target { private::XY::from_array(self.as_array()) }
}
impl<T: Element<3> + StoredVerbatim> core::ops::Deref for Vector<T, 3> {
type Target = private::XYZ<T>;
#[inline]
fn deref(&self) -> &Self::Target { private::XYZ::from_array(self.as_array()) }
}
impl<T: Element<4> + StoredVerbatim> core::ops::Deref for Vector<T, 4> {
type Target = private::XYZW<T>;
#[inline]
fn deref(&self) -> &Self::Target { private::XYZW::from_array(self.as_array()) }
}
impl<T: Element<2> + StoredVerbatim> core::ops::DerefMut for Vector<T, 2> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
private::XY::from_mut_array(self.as_mut_array())
}
}
impl<T: Element<3> + StoredVerbatim> core::ops::DerefMut for Vector<T, 3> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
private::XYZ::from_mut_array(self.as_mut_array())
}
}
impl<T: Element<4> + StoredVerbatim> core::ops::DerefMut for Vector<T, 4> {
#[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
private::XYZW::from_mut_array(self.as_mut_array())
}
}
impl<T: Element<R, C> + StoredVerbatim, const R: usize, const C: usize>
core::ops::Index<(usize, usize)> for row_major::Matrix<T, R, C>
{
type Output = T;
#[inline]
fn index(&self, (i, j): (usize, usize)) -> &Self::Output {
if let Some(value) = row_major::call!(<T, R, C>::index(&self.storage, (j, i))) {
value
} else {
std::hint::cold_path();
panic!(
"matrix index out of bounds: the dimensions are {R}x{C} but the index is ({i}, {j})"
)
}
}
}
impl<T: Element<R, C> + StoredVerbatim, const R: usize, const C: usize>
core::ops::IndexMut<(usize, usize)> for row_major::Matrix<T, R, C>
{
#[inline]
fn index_mut(&mut self, (i, j): (usize, usize)) -> &mut Self::Output {
if let Some(value) = row_major::call!(<T, R, C>::index_mut(&mut self.storage, (j, i))) {
value
} else {
std::hint::cold_path();
panic!(
"matrix index out of bounds: the dimensions are {R}x{C} but the index is ({i}, {j})"
)
}
}
}
impl<T: Element<R, C> + StoredVerbatim, const R: usize, const C: usize>
core::ops::Index<(usize, usize)> for column_major::Matrix<T, R, C>
{
type Output = T;
#[inline]
fn index(&self, (i, j): (usize, usize)) -> &Self::Output {
if let Some(value) = column_major::call!(<T, R, C>::index(&self.storage, (i, j))) {
value
} else {
std::hint::cold_path();
panic!(
"matrix index out of bounds: the dimensions are {R}x{C} but the index is ({i}, {j})"
)
}
}
}
impl<T: Element<R, C> + StoredVerbatim, const R: usize, const C: usize>
core::ops::IndexMut<(usize, usize)> for column_major::Matrix<T, R, C>
{
#[inline]
fn index_mut(&mut self, (i, j): (usize, usize)) -> &mut Self::Output {
if let Some(value) = column_major::call!(<T, R, C>::index_mut(&mut self.storage, (i, j))) {
value
} else {
std::hint::cold_path();
panic!(
"matrix index out of bounds: the dimensions are {R}x{C} but the index is ({i}, {j})"
)
}
}
}
impl<T: Element<D> + StoredVerbatim, const D: usize> core::ops::Index<usize> for Vector<T, D> {
type Output = T;
#[inline]
fn index(&self, index: usize) -> &Self::Output {
if let Some(value) = vector::call!(<T, D>::index(&self.storage, (index, 0))) {
value
} else {
std::hint::cold_path();
panic!("index out of bounds: the len is {D} but the index is {index}")
}
}
}
impl<T: Element<D> + StoredVerbatim, const D: usize> core::ops::IndexMut<usize> for Vector<T, D> {
#[inline]
fn index_mut(&mut self, index: usize) -> &mut Self::Output {
if let Some(value) = vector::call!(<T, D>::index_mut(&mut self.storage, (index, 0))) {
value
} else {
std::hint::cold_path();
panic!("index out of bounds: the len is {D} but the index is {index}")
}
}
}
impl<T: MaskElement<D>, const D: usize> Mask<T, D> {
#[inline]
pub fn splat(value: bool) -> Self { Self::from([value; D]) }
#[inline]
pub fn to_array(self) -> [bool; D] { vector::call!(<T, D>::to_bool_array(self.storage))[0] }
#[inline]
pub fn to_vector(self) -> Vector<T, D> {
vector::call!(Vector(<T, D>::from_mask(self.storage)))
}
#[inline]
pub fn all(self) -> bool { vector::call!(<T, D>::all(self.storage)) }
#[inline]
pub fn any(self) -> bool { vector::call!(<T, D>::any(self.storage)) }
}
impl<T, U, const D: usize> Select<Mask<T, D>> for Mask<U, D>
where
T: MaskElement<D>,
U: MaskElement<D>,
{
#[inline]
fn select(self, true_values: Mask<T, D>, false_values: Mask<T, D>) -> Mask<T, D> {
Mask {
storage: <T as private::SealedElement<D, 1>>::mask_select_any::<U>(
self.storage,
true_values.storage,
false_values.storage,
),
}
}
}
impl<T, U, const D: usize> Select<Vector<T, D>> for Mask<U, D>
where
T: Element<D>,
U: MaskElement<D>,
{
#[inline]
fn select(self, true_values: Vector<T, D>, false_values: Vector<T, D>) -> Vector<T, D> {
Vector {
storage: <T as private::SealedElement<D, 1>>::select_any_mask::<U>(
self.storage,
true_values.storage,
false_values.storage,
),
}
}
}