use std::borrow::{Borrow, BorrowMut};
use std::fmt::{self, Display, Formatter};
use std::iter::{FromIterator, Product, Sum};
use std::mem;
use std::ptr;
use std::cmp;
use std::ops::*;
use std::slice::{self, };
use num_traits::{Zero, One, NumCast, AsPrimitive, Signed, real::Real};
use approx::{AbsDiffEq, RelativeEq, UlpsEq};
use crate::ops::*;
#[cfg(feature = "platform_intrinsics")]
use crate::simd_llvm;
macro_rules! choose {
(c { c => $c_impl:expr, simd_llvm => $s_impl:expr, }) => {
{ $c_impl }
};
(simd { c => $c_impl:expr, simd_llvm => $s_impl:expr, }) => {
#[cfg(not(feature = "platform_intrinsics"))]
{ $c_impl }
#[cfg(feature = "platform_intrinsics")]
{ $s_impl }
};
}
macro_rules! cond_borrow {
(ref, $a:expr) => { &$a };
(move, $a:expr) => { $a };
}
macro_rules! reduce_fn {
($fn:expr, $a:expr, $b:expr) => { $fn($a, $b) };
($fn:expr, $a:expr, $b:expr, $($v:expr),+) => { reduce_fn!($fn, reduce_fn!($fn, $a, $b), $($v),+) };
}
macro_rules! reduce_fn_mut {
($fn:expr, $a:expr, $b:expr) => { $fn($a, $b) };
($fn:expr, $a:expr, $b:expr, $($v:expr),+) => { { let x = reduce_fn_mut!($fn, $a, $b); reduce_fn_mut!($fn, x, $($v),+) } };
}
macro_rules! reduce_binop {
($op:tt, $a:expr, $b:expr) => { $a $op $b };
($op:tt, $a:expr, $b:expr, $($v:expr),+) => { reduce_binop!($op, reduce_binop!($op, $a, $b), $($v),+) };
}
macro_rules! horizontal_binop {
($op:tt, $out:expr => $a:expr, $b:expr) => { $out = $a $op $b; };
($op:tt, $out:expr, $($vout:expr),+ => $a:expr, $b:expr, $($v:expr),+) => { horizontal_binop!($op, $out => $a, $b); horizontal_binop!($op, $($vout),+ => $($v),+); };
}
macro_rules! vec_impl_cmp {
($(#[$attrs:meta])*, $c_or_simd:ident, $Vec:ident, $cmp:ident, $simd_cmp:ident, $op:tt, $Bounds:tt, ($($get:tt)+)) => {
$(#[$attrs])*
#[inline]
pub fn $cmp<Rhs: AsRef<Self>>(&self, rhs: &Rhs) -> $Vec<bool> where T: $Bounds {
let rhs = rhs.as_ref();
choose!{$c_or_simd {
c => $Vec::new($(self.$get $op rhs.$get),+),
simd_llvm => unsafe { simd_llvm::$simd_cmp(self, rhs) },
}}
}
}
}
macro_rules! vec_impl_trinop_vec_vec {
($op:ident, $Out:ty, $Rhs1:ty, $Rhs2:ty, ($($namedget:ident)+) ($($get:tt)+) ($lborrow:tt) ($rborrow:tt)) => {
type Output = $Out;
#[inline]
fn $op(self, a: $Rhs1, b: $Rhs2) -> Self::Output {
Self::Output::new($(self.$get.$op(cond_borrow!($lborrow, a.$get), cond_borrow!($rborrow, b.$get))),+)
}
}
}
macro_rules! vec_impl_trinop {
(impl $Op:ident for $Vec:ident { $op:tt } ($($namedget:tt)+) ($($get:tt)+)) => {
impl< T> $Op< $Vec<T>, $Vec<T>> for $Vec<T> where T: $Op< T, T, Output=T> { vec_impl_trinop_vec_vec!{$op, $Vec<T>, $Vec<T>, $Vec<T>, ($($namedget)+) ($($get)+) (move) (move)} }
impl< 'c, T> $Op< $Vec<T>, $Vec<T>> for &'c $Vec<T> where &'c T: $Op< T, T, Output=T> { vec_impl_trinop_vec_vec!{$op, $Vec<T>, $Vec<T>, $Vec<T>, ($($namedget)+) ($($get)+) (move) (move)} }
impl< 'b, T> $Op< $Vec<T>, &'b $Vec<T>> for $Vec<T> where T: $Op< T, &'b T, Output=T> { vec_impl_trinop_vec_vec!{$op, $Vec<T>, $Vec<T>, &'b $Vec<T>, ($($namedget)+) ($($get)+) (move) (ref)} }
impl< 'b, 'c, T> $Op< $Vec<T>, &'b $Vec<T>> for &'c $Vec<T> where &'c T: $Op< T, &'b T, Output=T> { vec_impl_trinop_vec_vec!{$op, $Vec<T>, $Vec<T>, &'b $Vec<T>, ($($namedget)+) ($($get)+) (move) (ref)} }
impl<'a, T> $Op<&'a $Vec<T>, $Vec<T>> for $Vec<T> where T: $Op<&'a T, T, Output=T> { vec_impl_trinop_vec_vec!{$op, $Vec<T>, &'a $Vec<T>, $Vec<T>, ($($namedget)+) ($($get)+) (ref) (move)} }
impl<'a, 'c, T> $Op<&'a $Vec<T>, $Vec<T>> for &'c $Vec<T> where &'c T: $Op<&'a T, T, Output=T> { vec_impl_trinop_vec_vec!{$op, $Vec<T>, &'a $Vec<T>, $Vec<T>, ($($namedget)+) ($($get)+) (ref) (move)} }
impl<'a, 'b, T> $Op<&'a $Vec<T>, &'b $Vec<T>> for $Vec<T> where T: $Op<&'a T, &'b T, Output=T> { vec_impl_trinop_vec_vec!{$op, $Vec<T>, &'a $Vec<T>, &'b $Vec<T>, ($($namedget)+) ($($get)+) (ref) (ref)} }
impl<'a, 'b, 'c, T> $Op<&'a $Vec<T>, &'b $Vec<T>> for &'c $Vec<T> where &'c T: $Op<&'a T, &'b T, Output=T> { vec_impl_trinop_vec_vec!{$op, $Vec<T>, &'a $Vec<T>, &'b $Vec<T>, ($($namedget)+) ($($get)+) (ref) (ref)} }
}
}
macro_rules! vec_impl_binop_commutative {
($c_or_simd:ident, impl $Op:ident<$Vec:ident> for T { $op:tt, $simd_op:ident } where T = $($lhs:ident),+) => {
$(
impl $Op<$Vec<$lhs>> for $lhs {
type Output = $Vec<$lhs>;
#[inline]
fn $op(self, rhs: $Vec<$lhs>) -> Self::Output {
rhs.$op(self)
}
}
)+
}
}
macro_rules! vec_impl_binop {
($c_or_simd:ident, commutative impl $Op:ident for $Vec:ident { $op:tt, $simd_op:ident } ($($get:tt)+)) => {
vec_impl_binop!($c_or_simd, impl $Op for $Vec { $op, $simd_op } ($($get)+));
vec_impl_binop_commutative!($c_or_simd, impl $Op<$Vec> for T { $op, $simd_op } where T = i8, u8, i16, u16, i32, u32, i64, u64, f32, f64);
};
($c_or_simd:ident, impl $Op:ident for $Vec:ident { $op:tt, $simd_op:ident } ($($get:tt)+)) => {
impl<V, T> $Op<V> for $Vec<T> where V: Into<$Vec<T>>, T: $Op<T, Output=T> {
type Output = Self;
#[inline]
fn $op(self, rhs: V) -> Self::Output {
let rhs = rhs.into();
choose!{$c_or_simd {
c => $Vec::new($(self.$get.$op(rhs.$get)),+),
simd_llvm => unsafe { simd_llvm::$simd_op(self, rhs) },
}}
}
}
impl<'a, T> $Op<&'a $Vec<T>> for $Vec<T> where T: $Op<&'a T, Output=T> {
type Output = $Vec<T>;
#[inline]
fn $op(self, rhs: &'a $Vec<T>) -> Self::Output {
$Vec::new($(self.$get.$op(&rhs.$get)),+)
}
}
impl<'a, T> $Op<$Vec<T>> for &'a $Vec<T> where &'a T: $Op<T, Output=T> {
type Output = $Vec<T>;
#[inline]
fn $op(self, rhs: $Vec<T>) -> Self::Output {
$Vec::new($(self.$get.$op(rhs.$get)),+)
}
}
impl<'a, 'b, T> $Op<&'a $Vec<T>> for &'b $Vec<T> where &'b T: $Op<&'a T, Output=T> {
type Output = $Vec<T>;
#[inline]
fn $op(self, rhs: &'a $Vec<T>) -> Self::Output {
$Vec::new($(self.$get.$op(&rhs.$get)),+)
}
}
impl<'a, T> $Op<T> for &'a $Vec<T> where &'a T: $Op<T, Output=T>, T: Copy {
type Output = $Vec<T>;
#[inline]
fn $op(self, rhs: T) -> Self::Output {
$Vec::new($(self.$get.$op(rhs)),+)
}
}
impl<'a, 'b, T> $Op<&'a T> for &'b $Vec<T> where &'b T: $Op<&'a T, Output=T> {
type Output = $Vec<T>;
#[inline]
fn $op(self, rhs: &'a T) -> Self::Output {
$Vec::new($(self.$get.$op(rhs)),+)
}
}
};
}
macro_rules! vec_impl_binop_assign {
($c_or_simd:ident, impl $Op:ident for $Vec:ident { $op:tt } ($($get:tt)+)) => {
impl<V, T> $Op<V> for $Vec<T> where V: Into<$Vec<T>>, T: $Op<T> {
#[inline]
fn $op(&mut self, rhs: V) {
let rhs = rhs.into();
$(self.$get.$op(rhs.$get);)+
}
}
}
}
macro_rules! vec_impl_unop {
(impl $Op:ident for $Vec:ident { $op:tt } ($($get:tt)+)) => {
impl<T> $Op for $Vec<T> where T: $Op<Output=T> {
type Output = Self;
#[inline]
fn $op(self) -> Self::Output {
Self::new($(self.$get.$op()),+)
}
}
}
}
macro_rules! vec_impl_vec {
($c_or_simd:ident $repr_c:ident tuple $Vec:ident $vec:ident ($dim:expr) ($fmt:expr) ($fmt_prefix:expr) ($($get:tt)+) ($($namedget:tt)+) ($($tupleget:tt)+) $Tuple:ty) => {
impl<T> $Vec<T> {
#[cfg_attr(feature = "clippy", allow(too_many_arguments))]
pub const fn new($($namedget:T),+) -> Self {
$Vec($($namedget),+)
}
}
vec_impl_vec!{common $c_or_simd $Vec $vec ($dim) ($fmt) ($fmt_prefix) ($($get)+) ($($namedget)+) ($($tupleget)+) $Tuple}
vec_impl_vec!{specific $c_or_simd $repr_c $Vec $vec ($dim) ($fmt) ($fmt_prefix) ($($get)+) ($($namedget)+) ($($tupleget)+) $Tuple}
};
($c_or_simd:ident $repr_c:ident struct $Vec:ident $vec:ident ($dim:expr) ($fmt:expr) ($fmt_prefix:expr) ($($get:tt)+) ($($namedget:tt)+) ($($tupleget:tt)+) $Tuple:ty) => {
impl<T> $Vec<T> {
#[cfg_attr(feature = "clippy", allow(too_many_arguments))]
pub const fn new($($namedget:T),+) -> Self {
Self { $($namedget),+ }
}
}
vec_impl_vec!{common $c_or_simd $Vec $vec ($dim) ($fmt) ($fmt_prefix) ($($get)+) ($($namedget)+) ($($tupleget)+) $Tuple}
vec_impl_vec!{specific $c_or_simd $repr_c $Vec $vec ($dim) ($fmt) ($fmt_prefix) ($($get)+) ($($namedget)+) ($($tupleget)+) $Tuple}
};
(specific simd $repr_c:ident $Vec:ident $vec:ident ($dim:expr) ($fmt:expr) ($fmt_prefix:expr) ($($get:tt)+) ($($namedget:tt)+) ($($tupleget:tt)+) $Tuple:ty) => {
vec_impl_vec!{specificsimd $Vec $vec ($dim) ($fmt) ($fmt_prefix) ($($get)+) ($($namedget)+) ($($tupleget)+) $Tuple}
};
(specific c repr_simd $Vec:ident $vec:ident ($dim:expr) ($fmt:expr) ($fmt_prefix:expr) ($($get:tt)+) ($($namedget:tt)+) ($($tupleget:tt)+) $Tuple:ty) => {
vec_impl_vec!{specificsimd $Vec $vec ($dim) ($fmt) ($fmt_prefix) ($($get)+) ($($namedget)+) ($($tupleget)+) $Tuple}
};
(specific c repr_c $Vec:ident $vec:ident ($dim:expr) ($fmt:expr) ($fmt_prefix:expr) ($($get:tt)+) ($($namedget:tt)+) ($($tupleget:tt)+) $Tuple:ty) => {
use super::super::repr_c::$vec::$Vec as CVec;
};
(specificsimd $Vec:ident $vec:ident ($dim:expr) ($fmt:expr) ($fmt_prefix:expr) ($($get:tt)+) ($($namedget:tt)+) ($($tupleget:tt)+) $Tuple:ty) => {
use super::super::repr_c::$vec::$Vec as CVec;
impl<T> From<CVec<T>> for $Vec<T> {
fn from(v: CVec<T>) -> Self {
Self::new($(v.$get),+)
}
}
impl<T> From<$Vec<T>> for CVec<T> {
fn from(v: $Vec<T>) -> Self {
Self::new($(v.$get),+)
}
}
impl<T> $Vec<T> {
pub fn into_repr_c(self) -> CVec<T> {
self.into()
}
}
impl<T> CVec<T> {
pub fn into_repr_simd(self) -> $Vec<T> {
self.into()
}
}
};
(common $c_or_simd:ident $Vec:ident $vec:ident ($dim:expr) ($fmt:expr) ($fmt_prefix:expr) ($($get:tt)+) ($($namedget:tt)+) ($($tupleget:tt)+) $Tuple:ty) => {
#[allow(missing_docs)]
#[doc=$fmt]
impl<T: Display> Display for $Vec<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
write!(f, $fmt_prefix)?;
write!(f, "(")?;
let mut elems = self.iter();
if let Some(elem)=elems.next(){
write!(f, " ")?;
elem.fmt(f)?;
}
for elem in elems {
write!(f, ", ")?;
elem.fmt(f)?;
}
write!(f, " )")
}
}
impl<T> $Vec<T> {
#[inline]
pub fn broadcast(val: T) -> Self where T: Copy {
Self::new($({let $namedget = val; $namedget}),+)
}
#[inline]
pub fn zero() -> Self where T: Zero {
Self::new($({let $namedget = T::zero(); $namedget}),+)
}
#[inline]
pub fn one() -> Self where T: One {
Self::new($({let $namedget = T::one(); $namedget}),+)
}
pub fn iota() -> Self where T: Zero + One + AddAssign + Copy {
let mut i = T::zero();
$(
let $namedget = i;
i += T::one();
)+
Self::new($($namedget),+)
}
pub const fn elem_count(&self) -> usize {
$dim
}
pub const ELEM_COUNT: usize = $dim;
#[cfg_attr(feature = "clippy", allow(type_complexity))]
pub fn into_tuple(self) -> $Tuple {
($(self.$get),+)
}
#[cfg_attr(feature = "clippy", allow(type_complexity))]
pub fn into_array(self) -> [T; $dim] {
[$(self.$get, )+]
}
#[inline]
fn as_ptr_priv(&self) -> *const T {
self as *const _ as *const T
}
#[inline]
fn as_mut_ptr_priv(&mut self) -> *mut T {
self as *mut _ as *mut T
}
#[inline]
pub fn as_slice(&self) -> &[T] {
unsafe {
slice::from_raw_parts(self.as_ptr_priv(), $dim)
}
}
#[inline]
pub fn as_mut_slice(&mut self) -> &mut [T] {
unsafe {
slice::from_raw_parts_mut(self.as_mut_ptr_priv(), $dim)
}
}
pub fn from_slice(slice: &[T]) -> Self where T: Default + Copy {
Self::from_iter(slice.into_iter().cloned())
}
#[inline]
pub fn map<D,F>(self, mut f: F) -> $Vec<D> where F: FnMut(T) -> D {
$Vec::new($(f(self.$get)),+)
}
#[inline]
pub fn map2<D,F,S>(self, other: $Vec<S>, mut f: F) -> $Vec<D> where F: FnMut(T, S) -> D {
$Vec::new($(f(self.$get, other.$get)),+)
}
#[inline]
pub fn map3<D,F,S1,S2>(self, a: $Vec<S1>, b: $Vec<S2>, mut f: F) -> $Vec<D> where F: FnMut(T, S1, S2) -> D {
$Vec::new($(f(self.$get, a.$get, b.$get)),+)
}
#[inline]
pub fn apply<F>(&mut self, mut f: F) where T: Copy, F: FnMut(T) -> T {
$(self.$get = f(self.$get);)+
}
#[inline]
pub fn apply2<F, S>(&mut self, other: $Vec<S>, mut f: F) where T: Copy, F: FnMut(T, S) -> T {
$(self.$get = f(self.$get, other.$get);)+
}
#[inline]
pub fn apply3<F, S1, S2>(&mut self, a: $Vec<S1>, b: $Vec<S2>, mut f: F) where T: Copy, F: FnMut(T, S1, S2) -> T {
$(self.$get = f(self.$get, a.$get, b.$get);)+
}
pub fn zip<S>(self, other: $Vec<S>) -> $Vec<(T, S)> {
self.map2(other, |a, b| (a, b))
}
#[inline]
pub fn as_<D>(self) -> $Vec<D> where T: AsPrimitive<D>, D: 'static + Copy {
choose!{$c_or_simd {
c => $Vec::new($(self.$get.as_()),+),
simd_llvm => unsafe { simd_llvm::simd_cast(self) },
}}
}
pub fn numcast<D>(self) -> Option<$Vec<D>> where T: NumCast, D: NumCast {
Some($Vec::new($(match D::from(self.$get) {
Some(x) => x,
None => return None,
}),+))
}
#[inline]
pub fn mul_add<V0: Into<Self>, V1: Into<Self>>(self, mul: V0, add: V1) -> Self
where T: MulAdd<T,T,Output=T>
{
let mul = mul.into();
let add = add.into();
choose!{$c_or_simd {
c => $Vec::new($(self.$get.mul_add(mul.$get, add.$get)),+),
simd_llvm => unsafe { simd_llvm::simd_fma(self, mul, add) },
}}
}
#[inline]
pub fn is_any_negative(&self) -> bool where T: Signed {
reduce_binop!(||, $(self.$get.is_negative()),+)
}
#[inline]
pub fn are_all_positive(&self) -> bool where T: Signed {
reduce_binop!(&&, $(self.$get.is_positive()),+)
}
#[inline]
pub fn min<V0, V1>(a: V0, b: V1) -> Self where V0: Into<Self>, V1: Into<Self>, T: Ord {
let (a, b) = (a.into(), b.into());
Self::new($(cmp::min(a.$get, b.$get)),+)
}
#[inline]
pub fn max<V0, V1>(a: V0, b: V1) -> Self where V0: Into<Self>, V1: Into<Self>, T: Ord {
let (a, b) = (a.into(), b.into());
Self::new($(cmp::max(a.$get, b.$get)),+)
}
#[inline]
pub fn partial_min<V0, V1>(a: V0, b: V1) -> Self where V0: Into<Self>, V1: Into<Self>, T: PartialOrd {
let (a, b) = (a.into(), b.into());
Self::new($(partial_min(a.$get, b.$get)),+)
}
#[inline]
pub fn partial_max<V0, V1>(a: V0, b: V1) -> Self where V0: Into<Self>, V1: Into<Self>, T: PartialOrd {
let (a, b) = (a.into(), b.into());
Self::new($(partial_max(a.$get, b.$get)),+)
}
#[inline]
pub fn reduce_min(self) -> T where T: Ord {
choose!{$c_or_simd {
c => reduce_fn!(cmp::min, $(self.$get),+),
simd_llvm => unsafe { simd_llvm::simd_reduce_min(self) },
}}
}
#[inline]
pub fn reduce_max(self) -> T where T: Ord {
choose!{$c_or_simd {
c => reduce_fn!(cmp::max, $(self.$get),+),
simd_llvm => unsafe { simd_llvm::simd_reduce_max(self) },
}}
}
#[inline]
pub fn reduce_partial_min(self) -> T where T: PartialOrd {
choose!{$c_or_simd {
c => reduce_fn!(partial_min, $(self.$get),+),
simd_llvm => unsafe { simd_llvm::simd_reduce_min(self) },
}}
}
#[inline]
pub fn reduce_partial_max(self) -> T where T: PartialOrd {
choose!{$c_or_simd {
c => reduce_fn!(partial_max, $(self.$get),+),
simd_llvm => unsafe { simd_llvm::simd_reduce_max(self) },
}}
}
#[inline]
pub fn reduce_bitand(self) -> T where T: BitAnd<T, Output=T> {
choose!{$c_or_simd {
c => reduce_binop!(&, $(self.$get),+),
simd_llvm => unsafe { simd_llvm::simd_reduce_and(self) },
}}
}
#[inline]
pub fn reduce_bitor(self) -> T where T: BitOr<T, Output=T> {
choose!{$c_or_simd {
c => reduce_binop!(|, $(self.$get),+),
simd_llvm => unsafe { simd_llvm::simd_reduce_or(self) },
}}
}
#[inline]
pub fn reduce_bitxor(self) -> T where T: BitXor<T, Output=T> {
choose!{$c_or_simd {
c => reduce_binop!(^, $(self.$get),+),
simd_llvm => unsafe { simd_llvm::simd_reduce_xor(self) },
}}
}
#[inline]
pub fn reduce<F>(self, mut f: F) -> T where F: FnMut(T,T) -> T {
reduce_fn_mut!(f, $(self.$get),+)
}
#[inline]
pub fn product(self) -> T where T: Mul<Output=T> {
choose!{$c_or_simd {
c => reduce_binop!(*, $(self.$get),+),
simd_llvm => unsafe { simd_llvm::simd_reduce_mul_unordered(self) },
}}
}
#[inline]
pub fn sum(self) -> T where T: Add<T, Output=T> {
choose!{$c_or_simd {
c => reduce_binop!(+, $(self.$get),+),
simd_llvm => unsafe { simd_llvm::simd_reduce_add_unordered(self) },
}}
}
#[inline]
pub fn average(self) -> T where T: Add<T, Output=T> + Div<T, Output=T> + From<u8> {
self.sum() / T::from($dim as _)
}
#[inline]
pub fn sqrt(self) -> Self where T: Real {
choose!{$c_or_simd {
c => Self::new($(self.$get.sqrt()),+),
simd_llvm => unsafe { simd_llvm::simd_fsqrt(self) },
}}
}
#[inline]
pub fn rsqrt(self) -> Self where T: Real {
self.sqrt().recip()
}
#[inline]
pub fn recip(self) -> Self where T: Real {
Self::new($(self.$get.recip()),+)
}
#[inline]
pub fn ceil(self) -> Self where T: Real {
choose!{$c_or_simd {
c => Self::new($(self.$get.ceil()),+),
simd_llvm => unsafe { simd_llvm::simd_ceil(self) },
}}
}
#[inline]
pub fn floor(self) -> Self where T: Real {
choose!{$c_or_simd {
c => Self::new($(self.$get.floor()),+),
simd_llvm => unsafe { simd_llvm::simd_floor(self) },
}}
}
#[inline]
pub fn round(self) -> Self where T: Real {
Self::new($(self.$get.round()),+)
}
#[inline]
pub fn hadd(self, rhs: Self) -> Self where T: Add<T, Output=T> {
$(let $namedget;)+
horizontal_binop!(+, $($namedget),+ => $(self.$get,)+ $(rhs.$get),+);
Self::new($($namedget),+)
}
vec_impl_cmp!{
, $c_or_simd, $Vec, partial_cmpeq, simd_eq, ==, PartialEq, ($($get)+)
}
vec_impl_cmp!{
, $c_or_simd, $Vec, partial_cmpne, simd_ne, !=, PartialEq, ($($get)+)
}
vec_impl_cmp!{
, $c_or_simd, $Vec, partial_cmpge, simd_ge, >=, PartialOrd, ($($get)+)
}
vec_impl_cmp!{
, $c_or_simd, $Vec, partial_cmpgt, simd_gt, >, PartialOrd, ($($get)+)
}
vec_impl_cmp!{
, $c_or_simd, $Vec, partial_cmple, simd_le, <=, PartialOrd, ($($get)+)
}
vec_impl_cmp!{
, $c_or_simd, $Vec, partial_cmplt, simd_lt, <, PartialOrd, ($($get)+)
}
vec_impl_cmp!{
, $c_or_simd, $Vec, cmpeq, simd_eq, ==, Eq, ($($get)+)
}
vec_impl_cmp!{
, $c_or_simd, $Vec, cmpne, simd_ne, !=, Eq, ($($get)+)
}
vec_impl_cmp!{
, $c_or_simd, $Vec, cmpge, simd_ge, >=, Ord, ($($get)+)
}
vec_impl_cmp!{
, $c_or_simd, $Vec, cmpgt, simd_gt, >, Ord, ($($get)+)
}
vec_impl_cmp!{
, $c_or_simd, $Vec, cmple, simd_le, <=, Ord, ($($get)+)
}
vec_impl_cmp!{
, $c_or_simd, $Vec, cmplt, simd_lt, <, Ord, ($($get)+)
}
#[inline]
pub fn lerp_unclamped_precise<S: Into<Self>>(from: Self, to: Self, factor: S) -> Self
where T: Copy + One + Mul<Output=T> + Sub<Output=T> + MulAdd<T,T,Output=T>
{
let factor = factor.into();
from.mul_add(Self::one()-factor, to*factor)
}
#[inline]
pub fn lerp_unclamped<S: Into<Self>>(from: Self, to: Self, factor: S) -> Self
where T: Copy + Sub<Output=T> + MulAdd<T,T,Output=T>
{
let factor = factor.into();
factor.mul_add(to - from, from)
}
#[inline]
pub fn lerp<S: Into<Self> + Clamp + Zero + One>(from: Self, to: Self, factor: S) -> Self
where T: Copy + Sub<Output=T> + MulAdd<T,T,Output=T>
{
Self::lerp_unclamped(from, to, factor.clamped01().into())
}
#[inline]
pub fn lerp_precise<S: Into<Self> + Clamp + Zero + One>(from: Self, to: Self, factor: S) -> Self
where T: Copy + One + Mul<Output=T> + Sub<Output=T> + MulAdd<T,T,Output=T>
{
Self::lerp_unclamped_precise(from, to, factor.clamped01().into())
}
}
impl<T, Factor> Lerp<Factor> for $Vec<T>
where T: Lerp<Factor,Output=T>,
Factor: Copy
{
type Output = Self;
fn lerp_unclamped_precise(from: Self, to: Self, factor: Factor) -> Self {
Self::new($(Lerp::lerp_unclamped_precise(from.$get, to.$get, factor)),+)
}
fn lerp_unclamped(from: Self, to: Self, factor: Factor) -> Self {
Self::new($(Lerp::lerp_unclamped(from.$get, to.$get, factor)),+)
}
}
impl<'a, T, Factor> Lerp<Factor> for &'a $Vec<T>
where &'a T: Lerp<Factor,Output=T>,
Factor: Copy
{
type Output = $Vec<T>;
fn lerp_unclamped_precise(from: Self, to: Self, factor: Factor) -> $Vec<T> {
$Vec::new($(Lerp::lerp_unclamped_precise(&from.$get, &to.$get, factor)),+)
}
fn lerp_unclamped(from: Self, to: Self, factor: Factor) -> $Vec<T> {
$Vec::new($(Lerp::lerp_unclamped(&from.$get, &to.$get, factor)),+)
}
}
impl<T: Wrap + Copy> Wrap<T> for $Vec<T> {
fn wrapped(self, upper: T) -> Self {
self.wrapped(Self::broadcast(upper))
}
fn wrapped_between(self, lower: T, upper: T) -> Self {
self.wrapped_between(Self::broadcast(lower), Self::broadcast(upper))
}
fn pingpong(self, upper: T) -> Self {
self.pingpong(Self::broadcast(upper))
}
}
impl<T: Wrap> Wrap<$Vec<T>> for $Vec<T> {
fn wrapped(self, upper: $Vec<T>) -> Self {
Self::new($(self.$get.wrapped(upper.$get)),+)
}
fn wrapped_between(self, lower: Self, upper: Self) -> Self {
Self::new($(self.$get.wrapped_between(lower.$get, upper.$get)),+)
}
fn pingpong(self, upper: Self) -> Self {
Self::new($(self.$get.pingpong(upper.$get)),+)
}
}
impl<T: Clamp + Copy> Clamp<T> for $Vec<T> {
fn clamped(self, lower: T, upper: T) -> Self {
self.clamped(Self::broadcast(lower), Self::broadcast(upper))
}
}
impl<T: IsBetween<Output=bool> + Copy> IsBetween<T> for $Vec<T> {
type Output = $Vec<bool>;
fn is_between(self, lower: T, upper: T) -> Self::Output {
self.is_between(Self::broadcast(lower), Self::broadcast(upper))
}
}
impl<T: Clamp> Clamp<$Vec<T>> for $Vec<T> {
fn clamped(self, lower: Self, upper: Self) -> Self {
$Vec::new($(self.$get.clamped(lower.$get, upper.$get)),+)
}
}
impl<T: IsBetween<Output=bool>> IsBetween<$Vec<T>> for $Vec<T> {
type Output = $Vec<bool>;
fn is_between(self, lower: Self, upper: Self) -> Self::Output {
$Vec::new($(self.$get.is_between(lower.$get, upper.$get)),+)
}
}
impl<T: Zero + PartialEq> Zero for $Vec<T> {
fn zero() -> Self { Self::zero() }
fn is_zero(&self) -> bool { self == &Self::zero() }
}
impl<T: One> One for $Vec<T> {
fn one() -> Self { Self::one() }
}
impl<T: AbsDiffEq> AbsDiffEq for $Vec<T> where T::Epsilon: Copy {
type Epsilon = T::Epsilon;
fn default_epsilon() -> T::Epsilon {
T::default_epsilon()
}
#[inline]
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
reduce_binop!(&&, $(T::abs_diff_eq(&self.$get, &other.$get, epsilon)),+)
}
}
impl<T: UlpsEq> UlpsEq for $Vec<T> where T::Epsilon: Copy {
fn default_max_ulps() -> u32 {
T::default_max_ulps()
}
#[inline]
fn ulps_eq(&self, other: &Self, epsilon: T::Epsilon, max_ulps: u32) -> bool {
reduce_binop!(&&, $(T::ulps_eq(&self.$get, &other.$get, epsilon, max_ulps)),+)
}
}
impl<T: RelativeEq> RelativeEq for $Vec<T> where T::Epsilon: Copy {
fn default_max_relative() -> T::Epsilon {
T::default_max_relative()
}
#[inline]
fn relative_eq(&self, other: &Self, epsilon: T::Epsilon, max_relative: T::Epsilon) -> bool {
reduce_binop!(&&, $(T::relative_eq(&self.$get, &other.$get, epsilon, max_relative)),+)
}
}
impl $Vec<bool> {
#[inline]
pub fn reduce_and(self) -> bool {
choose!{$c_or_simd {
c => reduce_binop!(&&, $(self.$get),+),
simd_llvm => unsafe { simd_llvm::simd_reduce_all(self) },
}}
}
#[inline]
pub fn reduce_or(self) -> bool {
choose!{$c_or_simd {
c => reduce_binop!(||, $(self.$get),+),
simd_llvm => unsafe { simd_llvm::simd_reduce_any(self) },
}}
}
#[inline]
pub fn reduce_ne(self) -> bool {
reduce_binop!(!=, $(self.$get),+)
}
}
vec_impl_trinop!{impl MulAdd for $Vec { mul_add } ($($namedget)+) ($($get)+)}
vec_impl_unop!{ impl Neg for $Vec { neg } ($($get)+)}
vec_impl_binop!{$c_or_simd, commutative impl Add for $Vec { add, simd_add } ($($get)+)}
vec_impl_binop!{$c_or_simd, impl Sub for $Vec { sub, simd_sub } ($($get)+)}
vec_impl_binop!{$c_or_simd, commutative impl Mul for $Vec { mul, simd_mul } ($($get)+)}
vec_impl_binop!{$c_or_simd, impl Div for $Vec { div, simd_div } ($($get)+)}
vec_impl_binop!{c, impl Rem for $Vec { rem, simd_rem } ($($get)+)}
vec_impl_binop_assign!{$c_or_simd, impl AddAssign for $Vec { add_assign } ($($get)+)}
vec_impl_binop_assign!{$c_or_simd, impl SubAssign for $Vec { sub_assign } ($($get)+)}
vec_impl_binop_assign!{$c_or_simd, impl MulAssign for $Vec { mul_assign } ($($get)+)}
vec_impl_binop_assign!{$c_or_simd, impl DivAssign for $Vec { div_assign } ($($get)+)}
vec_impl_binop_assign!{$c_or_simd, impl RemAssign for $Vec { rem_assign } ($($get)+)}
vec_impl_binop!{$c_or_simd, impl Shl for $Vec { shl, simd_shl } ($($get)+)}
vec_impl_binop!{$c_or_simd, impl Shr for $Vec { shr, simd_shr } ($($get)+)}
vec_impl_binop_assign!{$c_or_simd, impl ShlAssign for $Vec { shl_assign } ($($get)+)}
vec_impl_binop_assign!{$c_or_simd, impl ShrAssign for $Vec { shr_assign } ($($get)+)}
vec_impl_binop!{$c_or_simd, impl BitAnd for $Vec { bitand, simd_and } ($($get)+)}
vec_impl_binop!{$c_or_simd, impl BitOr for $Vec { bitor , simd_or } ($($get)+)}
vec_impl_binop!{$c_or_simd, impl BitXor for $Vec { bitxor, simd_xor } ($($get)+)}
vec_impl_binop_assign!{$c_or_simd, impl BitAndAssign for $Vec { bitand_assign } ($($get)+)}
vec_impl_binop_assign!{$c_or_simd, impl BitOrAssign for $Vec { bitor_assign } ($($get)+)}
vec_impl_binop_assign!{$c_or_simd, impl BitXorAssign for $Vec { bitxor_assign } ($($get)+)}
vec_impl_unop!{ impl Not for $Vec { not } ($($get)+)}
impl<T> AsRef<[T]> for $Vec<T> {
#[inline]
fn as_ref(&self) -> &[T] {
self.as_slice()
}
}
impl<T> AsMut<[T]> for $Vec<T> {
#[inline]
fn as_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T> Borrow<[T]> for $Vec<T> {
#[inline]
fn borrow(&self) -> &[T] {
self.as_slice()
}
}
impl<T> BorrowMut<[T]> for $Vec<T> {
#[inline]
fn borrow_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
impl<T> AsRef<$Vec<T>> for $Vec<T> {
fn as_ref(&self) -> &Self {
self
}
}
impl<T> AsMut<$Vec<T>> for $Vec<T> {
fn as_mut(&mut self) -> &mut Self {
self
}
}
impl<'a, T> IntoIterator for &'a $Vec<T> {
type Item = &'a T;
type IntoIter = slice::Iter<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.as_slice().iter()
}
}
impl<'a, T> IntoIterator for &'a mut $Vec<T> {
type Item = &'a mut T;
type IntoIter = slice::IterMut<'a, T>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.as_mut_slice().iter_mut()
}
}
impl<T> Deref for $Vec<T> {
type Target = [T];
#[inline]
fn deref(&self) -> &[T] {
self.as_slice()
}
}
impl<T> DerefMut for $Vec<T> {
#[inline]
fn deref_mut(&mut self) -> &mut [T] {
self.as_mut_slice()
}
}
use std::mem::ManuallyDrop;
#[derive(Debug, Hash, PartialEq, Eq)]
pub struct IntoIter<T> {
vector: CVec<ManuallyDrop<T>>,
start: usize,
end: usize,
}
impl<T> Drop for IntoIter<T> {
fn drop(&mut self) {
for elem in &mut self.vector[self.start .. self.end] {
unsafe {
ManuallyDrop::drop(elem);
}
}
}
}
impl<T> IntoIterator for $Vec<T> {
type Item = T;
type IntoIter = IntoIter<T>;
fn into_iter(self) -> Self::IntoIter {
Self::IntoIter {
vector: CVec::from(self).map(ManuallyDrop::new),
start: 0,
end: $dim,
}
}
}
impl<T> Iterator for IntoIter<T> {
type Item = T;
fn next(&mut self) -> Option<Self::Item> {
if self.start == self.end {
return None;
}
unsafe {
let result = ManuallyDrop::into_inner(ptr::read(self.vector.get_unchecked(self.start)));
self.start += 1;
Some(result)
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let rem = self.len();
(rem, Some(rem))
}
}
impl<T> ExactSizeIterator for IntoIter<T> {
fn len(&self) -> usize {
self.end - self.start
}
}
impl<T> DoubleEndedIterator for IntoIter<T> {
fn next_back(&mut self) -> Option<T> {
if self.start == self.end {
return None;
}
unsafe {
self.end -= 1;
Some(ManuallyDrop::into_inner(ptr::read(self.vector.get_unchecked(self.end))))
}
}
}
impl<T: Default> FromIterator<T> for $Vec<T> {
fn from_iter<I>(iter: I) -> Self where I: IntoIterator<Item = T> {
let mut out = Self::default();
let mut iter = iter.into_iter();
for elem in &mut out {
if let Some(value) = iter.next() {
*elem = value
} else {
break;
}
}
out
}
}
impl<T> Sum for $Vec<T> where T: Add<T, Output=T> + Zero {
fn sum<I: Iterator<Item=$Vec<T>>>(iter: I) -> $Vec<T> {
iter.fold(Self::zero(), Add::add)
}
}
impl<T> Product for $Vec<T> where T: Mul<T, Output=T> + One {
fn product<I: Iterator<Item=$Vec<T>>>(iter: I) -> $Vec<T> {
iter.fold(Self::one(), Mul::mul)
}
}
#[cfg_attr(feature = "clippy", allow(type_complexity))]
impl<T> From<$Tuple> for $Vec<T> {
fn from(tuple: $Tuple) -> Self {
Self::new($(tuple.$tupleget),+)
}
}
#[cfg_attr(feature = "clippy", allow(type_complexity))]
impl<T> From<[T; $dim]> for $Vec<T> {
fn from(array: [T; $dim]) -> Self {
let array = mem::ManuallyDrop::new(array);
let mut i = -1_isize;
$(
i += 1;
let $namedget = unsafe {
ptr::read(array.get_unchecked(i as usize))
};
)+
Self::new($($namedget),+)
}
}
impl<T: Copy> From<T> for $Vec<T> {
#[inline]
fn from(val: T) -> Self {
Self::broadcast(val)
}
}
};
}
macro_rules! vec_impl_spatial {
($Vec:ident) => {
impl<T> $Vec<T> {
#[inline]
pub fn dot(self, v: Self) -> T where T: Add<T, Output=T> + Mul<Output=T> {
(self * v).sum()
}
#[inline]
pub fn magnitude_squared(self) -> T where T: Copy + Add<T, Output=T> + Mul<Output=T> {
self.dot(self)
}
#[inline]
pub fn magnitude(self) -> T where T: Add<T, Output=T> + Real {
self.magnitude_squared().sqrt()
}
#[inline]
pub fn distance_squared(self, v: Self) -> T where T: Copy + Add<T, Output=T> + Sub<Output=T> + Mul<Output=T> {
(self - v).magnitude_squared()
}
#[inline]
pub fn distance(self, v: Self) -> T where T: Add<T, Output=T> + Real {
(self - v).magnitude()
}
#[inline]
pub fn normalized(self) -> Self where T: Add<T, Output=T> + Real {
self / self.magnitude()
}
pub fn try_normalized<E>(self) -> Option<Self>
where
T: RelativeEq<Epsilon = E> + Add<T, Output=T> + Real,
E: Add<Output = E> + Real,
{
if self.is_approx_zero() {
None
} else {
Some(self.normalized())
}
}
#[inline]
pub fn normalize(&mut self) where T: Add<T, Output=T> + Real {
*self = self.normalized();
}
#[inline]
pub fn is_normalized<E>(self) -> bool
where
T: RelativeEq<Epsilon = E> + Add<T, Output=T> + Real,
E: Real,
{
self.is_magnitude_close_to(T::one())
}
#[inline]
pub fn is_approx_zero<E>(self) -> bool
where
T: RelativeEq<Epsilon = E> + Add<T, Output=T> + Real,
E: Real,
{
self.is_magnitude_close_to(T::zero())
}
pub fn is_magnitude_close_to<E>(self, x: T) -> bool
where
T: RelativeEq<Epsilon = E> + Add<T, Output=T> + Real,
E: Real,
{
let epsilon = T::default_epsilon();
let max_rel = T::default_max_relative();
let four_epsilon = epsilon + epsilon + epsilon + epsilon;
let four_max_rel = max_rel + max_rel + max_rel + max_rel;
let x_squared = x * x;
self.magnitude_squared()
.relative_eq(&(x_squared), four_epsilon, four_max_rel)
}
pub fn angle_between(self, v: Self) -> T where T: Add<T, Output=T> + Real + Clamp {
self.normalized().dot(v.normalized()).clamped_minus1_1().acos()
}
#[deprecated(note="Use `to_degrees()` on the value returned by `angle_between()` instead")]
pub fn angle_between_degrees(self, v: Self) -> T
where T: Add<T, Output=T> + Real + Clamp
{
self.angle_between(v).to_degrees()
}
pub fn reflected(self, surface_normal: Self) -> Self
where T: Copy + Add<T, Output=T> + Mul<Output=T> + Sub<Output=T> + Add<Output=T>
{
let dot = self.dot(surface_normal);
self - surface_normal * (dot + dot)
}
pub fn refracted(self, surface_normal: Self, eta: T) -> Self
where T: Real + Add<T, Output=T> + Mul<Output=T>
{
let n = surface_normal;
let i = self;
let n_dot_i = n.dot(i);
let k = T::one() - eta * eta * (T::one() - n_dot_i * n_dot_i);
if k < T::zero() {
Self::zero()
} else {
i * eta - n * (eta * n_dot_i + k.sqrt())
}
}
pub fn face_forward(self, incident: Self, reference: Self) -> Self
where T: Add<T, Output=T> + Mul<Output=T> + Zero + PartialOrd + Neg<Output=T>
{
if reference.dot(incident) <= T::zero() {
self
} else {
-self
}
}
}
};
}
#[allow(unused_macros)]
macro_rules! vec_impl_spatial_2d {
($Vec:ident) => {
impl<T> $Vec<T> {
#[inline]
pub fn determine_side(self, a: Self, b: Self) -> T
where T: Copy + Sub<Output=T> + Mul<Output=T>
{
let (cx, cy) = self.into_tuple();
let (ax, ay) = a.into_tuple();
let (bx, by) = b.into_tuple();
let d1 = (bx - ax) * (cy - ay);
let d2 = (by - ay) * (cx - ax);
d1 - d2
}
pub fn signed_triangle_area(a: Self, b: Self, c: Self) -> T
where T: Copy + Sub<Output=T> + Mul<Output=T> + One + Div<Output=T> + Add<Output=T>
{
let two = T::one() + T::one();
c.determine_side(a, b)/two
}
pub fn triangle_area(a: Self, b: Self, c: Self) -> T
where T: Copy + Sub<Output=T> + Mul<Output=T> + One + Div<Output=T> + Add<Output=T> + PartialOrd + Neg<Output=T>
{
let s = Self::signed_triangle_area(a, b, c);
partial_max(s, -s)
}
#[inline]
pub fn rotated_z(self, angle_radians: T) -> Self where T: Real {
let c = angle_radians.cos();
let s = angle_radians.sin();
let Self { x, y } = self;
Self::new(c*x - s*y, s*x + c*y)
}
#[inline]
pub fn rotate_z(&mut self, angle_radians: T) where T: Real {
*self = self.rotated_z(angle_radians);
}
pub fn unit_x () -> Self where T: Zero + One { Self::new(T::one(), T::zero()) }
pub fn unit_y () -> Self where T: Zero + One { Self::new(T::zero(), T::one()) }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn left () -> Self where T: Zero + One + Neg<Output=T> { -Self::unit_x() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn right () -> Self where T: Zero + One { Self::unit_x() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn up () -> Self where T: Zero + One { Self::unit_y() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn down () -> Self where T: Zero + One + Neg<Output=T> { -Self::unit_y() }
}
};
}
#[allow(unused_macros)]
macro_rules! vec_impl_spatial_3d {
($($Vec:ident)+) => {
$(
impl<T> $Vec<T> {
pub fn new_point_2d(x: T, y: T) -> Self where T: One {
Self::new(x, y, T::one())
}
pub fn new_direction_2d(x: T, y: T) -> Self where T: Zero {
Self::new(x, y, T::zero())
}
pub fn from_point_2d<V: Into<Vec2<T>>>(v: V) -> Self where T: One {
let Vec2 { x, y } = v.into();
Self::new_point_2d(x, y)
}
pub fn from_direction_2d<V: Into<Vec2<T>>>(v: V) -> Self where T: Zero {
let Vec2 { x, y } = v.into();
Self::new_direction_2d(x, y)
}
#[inline]
pub fn cross(self, b: Self)
-> Self where T: Copy + Mul<Output=T> + Sub<Output=T>
{
let a = self;
Self::new(
a.y*b.z - a.z*b.y,
a.z*b.x - a.x*b.z,
a.x*b.y - a.y*b.x
)
}
pub fn slerp_unclamped(from: Self, to: Self, factor: T) -> Self
where T: Add<T, Output=T> + Real + Clamp + Lerp<T,Output=T>
{
let (mag_from, mag_to) = (from.magnitude(), to.magnitude());
let (from, to) = (from/mag_from, to/mag_to);
let cos_alpha = from.dot(to).clamped_minus1_1();
let alpha = cos_alpha.acos();
let sin_alpha = alpha.sin();
let t1 = ((T::one() - factor) * alpha).sin() / sin_alpha;
let t2 = (factor * alpha).sin() / sin_alpha;
(from * t1 + to * t2) * Lerp::lerp_unclamped(mag_from, mag_to, factor)
}
pub fn slerp(from: Self, to: Self, factor: T) -> Self
where T: Add<T, Output=T> + Real + Clamp + Lerp<T,Output=T>
{
Slerp::slerp(from, to, factor)
}
pub fn unit_x () -> Self where T: Zero + One { Self::new(T::one(), T::zero(), T::zero()) }
pub fn unit_y () -> Self where T: Zero + One { Self::new(T::zero(), T::one(), T::zero()) }
pub fn unit_z () -> Self where T: Zero + One { Self::new(T::zero(), T::zero(), T::one()) }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn left () -> Self where T: Zero + One + Neg<Output=T> { -Self::unit_x() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn right () -> Self where T: Zero + One { Self::unit_x() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn up () -> Self where T: Zero + One { Self::unit_y() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn down () -> Self where T: Zero + One + Neg<Output=T> { -Self::unit_y() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn forward_lh() -> Self where T: Zero + One { Self::unit_z() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn forward_rh() -> Self where T: Zero + One + Neg<Output=T> { -Self::unit_z() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn back_lh () -> Self where T: Zero + One + Neg<Output=T> { -Self::unit_z() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn back_rh () -> Self where T: Zero + One { Self::unit_z() }
}
impl<T> Slerp<T> for $Vec<T>
where T: Add<T, Output=T> + Real + Clamp + Lerp<T,Output=T>
{
type Output = Self;
fn slerp_unclamped(from: Self, to: Self, factor: T) -> Self {
Self::slerp_unclamped(from, to, factor)
}
}
)+
}
}
macro_rules! vec_impl_spatial_4d {
($($Vec:ident)+) => {
$(
impl<T> $Vec<T> {
pub fn new_point(x: T, y: T, z: T) -> Self where T: One {
Self::new(x, y, z, T::one())
}
pub fn new_direction(x: T, y: T, z: T) -> Self where T: Zero {
Self::new(x, y, z, T::zero())
}
pub fn from_point<V: Into<Vec3<T>>>(v: V) -> Self where T: One {
let Vec3 { x, y, z } = v.into();
Self::new_point(x, y, z)
}
pub fn from_direction<V: Into<Vec3<T>>>(v: V) -> Self where T: Zero {
let Vec3 { x, y, z } = v.into();
Self::new_direction(x, y, z)
}
pub fn unit_x () -> Self where T: Zero + One { Self::new(T::one(), T::zero(), T::zero(), T::zero()) }
pub fn unit_y () -> Self where T: Zero + One { Self::new(T::zero(), T::one(), T::zero(), T::zero()) }
pub fn unit_z () -> Self where T: Zero + One { Self::new(T::zero(), T::zero(), T::one(), T::zero()) }
pub fn unit_w () -> Self where T: Zero + One { Self::new(T::zero(), T::zero(), T::zero(), T::one()) }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn left () -> Self where T: Zero + One + Neg<Output=T> { -Self::unit_x() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn right () -> Self where T: Zero + One { Self::unit_x() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn up () -> Self where T: Zero + One { Self::unit_y() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn down () -> Self where T: Zero + One + Neg<Output=T> { -Self::unit_y() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn forward_lh() -> Self where T: Zero + One { Self::unit_z() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn forward_rh() -> Self where T: Zero + One + Neg<Output=T> { -Self::unit_z() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn back_lh () -> Self where T: Zero + One + Neg<Output=T> { -Self::unit_z() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn back_rh () -> Self where T: Zero + One { Self::unit_z() }
pub fn unit_x_point () -> Self where T: Zero + One { Self::new(T::one(), T::zero(), T::zero(), T::one()) }
pub fn unit_y_point () -> Self where T: Zero + One { Self::new(T::zero(), T::one(), T::zero(), T::one()) }
pub fn unit_z_point () -> Self where T: Zero + One { Self::new(T::zero(), T::zero(), T::one(), T::one()) }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn left_point () -> Self where T: Zero + One + Neg<Output=T> { Self::new(-T::one(), T::zero(), T::zero(), T::one()) }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn right_point () -> Self where T: Zero + One { Self::unit_x_point() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn up_point () -> Self where T: Zero + One { Self::unit_y_point() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn down_point () -> Self where T: Zero + One + Neg<Output=T> { Self::new(T::zero(), -T::one(), T::zero(), T::one()) }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn forward_point_lh() -> Self where T: Zero + One { Self::unit_z_point() }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn forward_point_rh() -> Self where T: Zero + One + Neg<Output=T> { Self::new(T::zero(), T::zero(), -T::one(), T::one()) }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn back_point_lh () -> Self where T: Zero + One + Neg<Output=T> { Self::new(T::zero(), T::zero(), -T::one(), T::one()) }
#[deprecated(since = "0.14.0", note = "This function is opinionated about the semantics of X,Y and Z axii, and should not be used. The mapping of axii (X,Y,Z) to perceived directions (e.g right, up, forward) is not universal at all and varies between libraries, graphics APIs, content creation tools and engines. If you want such helper functions, you should write these yourself as part of the package you're working on, according to what you know about YOUR current coordinate space.")]
pub fn back_point_rh () -> Self where T: Zero + One { Self::unit_z_point() }
pub fn homogenized(self) -> Self where T: Div<Output=T>, T: Copy {
self / self.w
}
pub fn homogenize(&mut self) where T: Div<Output=T>, T: Copy {
*self = self.homogenized();
}
pub fn is_homogeneous(self) -> bool where T: RelativeEq + Zero + One + Copy {
self.is_point() || self.is_direction()
}
pub fn is_point(self) -> bool where T: RelativeEq + One {
self.w.relative_eq(&T::one(), T::default_epsilon(), T::default_max_relative())
}
pub fn is_direction(self) -> bool where T: RelativeEq + Zero {
self.w.relative_eq(&T::zero(), T::default_epsilon(), T::default_max_relative())
}
}
)+
}
}
#[cfg(feature="image")]
macro_rules! vec_impl_pixel_rgb {
($Vec:ident) => {
extern crate image;
use self::image::{Primitive, Pixel, ColorType, Luma, LumaA};
impl<T> Pixel for $Vec<T>
where T: ColorComponent + Copy + Clone + Primitive
{
type Subpixel = T;
fn channel_count() -> u8 {
3
}
fn channels(&self) -> &[Self::Subpixel] {
self.as_slice()
}
fn channels_mut(&mut self) -> &mut [Self::Subpixel] {
self.as_mut_slice()
}
fn color_model() -> &'static str {
"RGB"
}
fn color_type() -> ColorType {
ColorType::RGB(Self::channel_count() * mem::size_of::<T>() as u8 * 8_u8)
}
fn channels4(&self) -> (Self::Subpixel, Self::Subpixel, Self::Subpixel, Self::Subpixel) {
(self.r, self.g, self.b, T::full())
}
fn from_channels(a: Self::Subpixel, b: Self::Subpixel, c: Self::Subpixel, _d: Self::Subpixel) -> Self {
Self::new(a, b, c)
}
fn from_slice(slice: &[Self::Subpixel]) -> &Self {
assert!(slice.len() >= Self::channel_count() as _);
unsafe { &*(slice.as_ptr() as *const _ as *const Self) }
}
fn from_slice_mut(slice: &mut [Self::Subpixel]) -> &mut Self {
assert!(slice.len() >= Self::channel_count() as _);
unsafe { &mut *(slice.as_mut_ptr() as *mut _ as *mut Self) }
}
fn to_rgb(&self) -> image::Rgb<Self::Subpixel> {
image::Rgb { data: [self.r, self.g, self.b] }
}
fn to_rgba(&self) -> image::Rgba<Self::Subpixel> {
image::Rgba { data: [self.r, self.g, self.b, T::full()] }
}
fn to_luma(&self) -> Luma<Self::Subpixel> {
let three = T::one() + T::one() + T::one();
let c = (self.r + self.g + self.b) / three;
Luma { data: [c] }
}
fn to_luma_alpha(&self) -> LumaA<Self::Subpixel> {
LumaA { data: [self.to_luma().data[0], T::full()] }
}
fn map<F>(&self, mut f: F) -> Self where F: FnMut(Self::Subpixel) -> Self::Subpixel {
Self { r: f(self.r), g: f(self.g), b: f(self.b) }
}
fn apply<F>(&mut self, f: F) where F: FnMut(Self::Subpixel) -> Self::Subpixel {
*self = Pixel::map(self, f);
}
fn map_with_alpha<F, G>(&self, mut f: F, mut _g: G) -> Self
where F: FnMut(Self::Subpixel) -> Self::Subpixel, G: FnMut(Self::Subpixel) -> Self::Subpixel
{
Self { r: f(self.r), g: f(self.g), b: f(self.b) }
}
fn apply_with_alpha<F, G>(&mut self, f: F, g: G)
where F: FnMut(Self::Subpixel) -> Self::Subpixel, G: FnMut(Self::Subpixel) -> Self::Subpixel
{
*self = self.map_with_alpha(f, g);
}
fn map2<F>(&self, other: &Self, mut f: F) -> Self
where F: FnMut(Self::Subpixel, Self::Subpixel) -> Self::Subpixel
{
Self {
r: f(self.r, other.r),
g: f(self.g, other.g),
b: f(self.b, other.b)
}
}
fn apply2<F>(&mut self, other: &Self, f: F)
where F: FnMut(Self::Subpixel, Self::Subpixel) -> Self::Subpixel
{
*self = self.map2(*other, f);
}
fn invert(&mut self) {
*self = self.inverted_rgb();
}
fn blend(&mut self, other: &Self) {
self.apply2(*other, |a, b| {
let a = <f64 as NumCast>::from(a).unwrap();
let b = <f64 as NumCast>::from(b).unwrap();
let m = (a+b)/2f64;
<T as NumCast>::from(m.round()).unwrap()
});
}
}
}
}
#[cfg(feature="image")]
macro_rules! vec_impl_pixel_rgba {
($Vec:ident) => {
extern crate image;
use self::image::{Primitive, Pixel, ColorType, Luma, LumaA};
impl<T> Pixel for $Vec<T>
where T: ColorComponent + Copy + Clone + Primitive
{
type Subpixel = T;
fn channel_count() -> u8 {
4
}
fn channels(&self) -> &[Self::Subpixel] {
self.as_slice()
}
fn channels_mut(&mut self) -> &mut [Self::Subpixel] {
self.as_mut_slice()
}
fn color_model() -> &'static str {
"RGBA"
}
fn color_type() -> ColorType {
ColorType::RGBA(Self::channel_count() * mem::size_of::<T>() as u8 * 8_u8)
}
fn channels4(&self) -> (Self::Subpixel, Self::Subpixel, Self::Subpixel, Self::Subpixel) {
(self.r, self.g, self.b, self.a)
}
fn from_channels(a: Self::Subpixel, b: Self::Subpixel, c: Self::Subpixel, d: Self::Subpixel) -> Self {
Self::new(a, b, c, d)
}
fn from_slice(slice: &[Self::Subpixel]) -> &Self {
assert!(slice.len() >= Self::channel_count() as _);
unsafe { &*(slice.as_ptr() as *const _ as *const Self) }
}
fn from_slice_mut(slice: &mut [Self::Subpixel]) -> &mut Self {
assert!(slice.len() >= Self::channel_count() as _);
unsafe { &mut *(slice.as_mut_ptr() as *mut _ as *mut Self) }
}
fn to_rgb(&self) -> image::Rgb<Self::Subpixel> {
image::Rgb { data: [self.r, self.g, self.b] }
}
fn to_rgba(&self) -> image::Rgba<Self::Subpixel> {
image::Rgba { data: [self.r, self.g, self.b, self.a] }
}
fn to_luma(&self) -> Luma<Self::Subpixel> {
let three = T::one() + T::one() + T::one();
let c = (self.r + self.g + self.b) / three;
Luma { data: [c] }
}
fn to_luma_alpha(&self) -> LumaA<Self::Subpixel> {
LumaA { data: [self.to_luma().data[0], self.a] }
}
fn map<F>(&self, mut f: F) -> Self where F: FnMut(Self::Subpixel) -> Self::Subpixel {
Self { r: f(self.r), g: f(self.g), b: f(self.b), a: f(self.a) }
}
fn apply<F>(&mut self, f: F) where F: FnMut(Self::Subpixel) -> Self::Subpixel {
*self = Pixel::map(self, f);
}
fn map_with_alpha<F, G>(&self, mut f: F, mut g: G) -> Self
where F: FnMut(Self::Subpixel) -> Self::Subpixel, G: FnMut(Self::Subpixel) -> Self::Subpixel
{
Self { r: f(self.r), g: f(self.g), b: f(self.b), a: g(self.a) }
}
fn apply_with_alpha<F, G>(&mut self, f: F, g: G)
where F: FnMut(Self::Subpixel) -> Self::Subpixel, G: FnMut(Self::Subpixel) -> Self::Subpixel
{
*self = self.map_with_alpha(f, g);
}
fn map2<F>(&self, other: &Self, mut f: F) -> Self
where F: FnMut(Self::Subpixel, Self::Subpixel) -> Self::Subpixel
{
Self {
r: f(self.r, other.r),
g: f(self.g, other.g),
b: f(self.b, other.b),
a: f(self.a, other.a)
}
}
fn apply2<F>(&mut self, other: &Self, f: F)
where F: FnMut(Self::Subpixel, Self::Subpixel) -> Self::Subpixel
{
*self = self.map2(*other, f);
}
fn invert(&mut self) {
*self = self.inverted_rgb();
}
fn blend(&mut self, other: &Self) {
self.apply2(*other, |a, b| {
let a = <f64 as NumCast>::from(a).unwrap();
let b = <f64 as NumCast>::from(b).unwrap();
let m = (a+b)/2f64;
<T as NumCast>::from(m.round()).unwrap()
});
}
}
}
}
#[cfg(feature="rgba")]
macro_rules! vec_impl_color_rgba {
($Vec:ident) => {
#[cfg(feature="image")]
vec_impl_pixel_rgba!{$Vec}
impl<T: ColorComponent> Rgba<T> {
pub fn new_opaque(r: T, g: T, b: T) -> Self {
Self::new(r, g, b, T::full())
}
pub fn new_transparent(r: T, g: T, b: T) -> Self {
Self::new(r, g, b, T::zero())
}
#[cfg(feature="rgb")]
pub fn from_opaque<V: Into<Rgb<T>>>(color: V) -> Self {
let Rgb { r, g, b } = color.into();
Self::new_opaque(r, g, b)
}
#[cfg(feature="rgb")]
pub fn from_transparent<V: Into<Rgb<T>>>(color: V) -> Self {
let Rgb { r, g, b } = color.into();
Self::new_transparent(r, g, b)
}
}
impl<T> Rgba<T> {
#[cfg(feature="rgb")]
pub fn from_translucent<V: Into<Rgb<T>>>(color: V, opacity: T) -> Self {
let Rgb { r, g, b } = color.into();
Self::new(r, g, b, opacity)
}
}
#[allow(missing_docs)]
impl<T: ColorComponent> $Vec<T> {
pub fn black () -> Self { Self::new_opaque(T::zero(), T::zero(), T::zero()) }
pub fn white () -> Self { Self::new_opaque(T::full(), T::full(), T::full()) }
pub fn red () -> Self { Self::new_opaque(T::full(), T::zero(), T::zero()) }
pub fn green () -> Self { Self::new_opaque(T::zero(), T::full(), T::zero()) }
pub fn blue () -> Self { Self::new_opaque(T::zero(), T::zero(), T::full()) }
pub fn cyan () -> Self { Self::new_opaque(T::zero(), T::full(), T::full()) }
pub fn magenta () -> Self { Self::new_opaque(T::full(), T::zero(), T::full()) }
pub fn yellow () -> Self { Self::new_opaque(T::full(), T::full(), T::zero()) }
pub fn gray(value: T) -> Self where T: Copy { Self::new_opaque(value, value, value) }
pub fn grey(value: T) -> Self where T: Copy { Self::gray(value) }
pub fn inverted_rgb(mut self) -> Self where T: Sub<Output=T> {
self.r = T::full() - self.r;
self.g = T::full() - self.g;
self.b = T::full() - self.b;
self
}
pub fn average_rgb(self) -> T where T: Add<T, Output=T> + Div<T, Output=T> + From<u8> {
let Self { r, g, b, .. } = self;
(r+g+b) / T::from(3)
}
}
impl<T> $Vec<T> {
pub fn shuffled_argb(self) -> Self {
let Self { r, g, b, a } = self;
Self::new(a, r, g, b)
}
pub fn shuffled_bgra(self) -> Self {
let Self { r, g, b, a } = self;
Self::new(b, g, r, a)
}
}
};
}
#[cfg(feature="rgb")]
macro_rules! vec_impl_color_rgb {
($Vec:ident) => {
#[cfg(feature="image")]
vec_impl_pixel_rgb!{$Vec}
#[allow(missing_docs)]
impl<T: ColorComponent> $Vec<T> {
pub fn black () -> Self { Self::new(T::zero(), T::zero(), T::zero()) }
pub fn white () -> Self { Self::new(T::full(), T::full(), T::full()) }
pub fn red () -> Self { Self::new(T::full(), T::zero(), T::zero()) }
pub fn green () -> Self { Self::new(T::zero(), T::full(), T::zero()) }
pub fn blue () -> Self { Self::new(T::zero(), T::zero(), T::full()) }
pub fn cyan () -> Self { Self::new(T::zero(), T::full(), T::full()) }
pub fn magenta () -> Self { Self::new(T::full(), T::zero(), T::full()) }
pub fn yellow () -> Self { Self::new(T::full(), T::full(), T::zero()) }
pub fn gray(value: T) -> Self where T: Copy { Self::new(value, value, value) }
pub fn grey(value: T) -> Self where T: Copy { Self::new(value, value, value) }
pub fn inverted_rgb(mut self) -> Self where T: Sub<Output=T> {
self.r = T::full() - self.r;
self.g = T::full() - self.g;
self.b = T::full() - self.b;
self
}
pub fn average_rgb(self) -> T where T: Add<T, Output=T> + Div<T, Output=T> + From<u8> {
let Self { r, g, b, .. } = self;
(r+g+b) / T::from(3)
}
}
impl<T> $Vec<T> {
pub fn shuffled_bgr(self) -> Self {
let Self { r, g, b } = self;
Self::new(b, g, r)
}
}
}
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
pub struct ShuffleMask4(u8);
impl From<usize> for ShuffleMask4 {
fn from(m: usize) -> Self {
Self::new(m,m,m,m)
}
}
impl From<(usize, usize, usize, usize)> for ShuffleMask4 {
fn from(tuple: (usize, usize, usize, usize)) -> Self {
let (a,b,c,d) = tuple;
Self::new(a,b,c,d)
}
}
impl From<[usize; 4]> for ShuffleMask4 {
fn from(m: [usize; 4]) -> Self {
Self::new(m[0], m[1], m[2], m[3])
}
}
impl ShuffleMask4 {
#[inline]
pub fn new(m0: usize, m1: usize, m2: usize, m3: usize) -> Self {
ShuffleMask4(((m0&3) | ((m1&3)<<2) | ((m2&3)<<4) | ((m3&3)<<6)) as _)
}
pub fn to_indices(&self) -> (usize, usize, usize, usize) {
let m = self.0 as usize;
(m&3, (m>>2)&3, (m>>4)&3, (m>>6)&3)
}
}
macro_rules! vec_impl_shuffle_4d {
($Vec:ident ($x:tt $y:tt $z:tt $w:tt)) => {
use super::super::ShuffleMask4;
impl<T> $Vec<T> {
pub fn shuffled<M: Into<ShuffleMask4>>(self, mask: M) -> Self where T: Copy {
Self::shuffle_lo_hi(self, self, mask)
}
pub fn shuffled_0101(self) -> Self where T: Copy {
Self::shuffle_lo_hi_0101(self, self)
}
pub fn shuffled_2323(self) -> Self where T: Copy {
Self::shuffle_hi_lo_2323(self, self)
}
pub fn shuffle_lo_hi<M: Into<ShuffleMask4>>(lo: Self, hi: Self, mask: M) -> Self where T: Copy {
let (lo0, lo1, hi2, hi3) = mask.into().to_indices();
Self::new(lo[lo0], lo[lo1], hi[hi2], hi[hi3])
}
pub fn interleave_0011(a: Self, b: Self) -> Self {
Self::new(a.$x, b.$x, a.$y, b.$y)
}
pub fn interleave_2233(a: Self, b: Self) -> Self {
Self::new(a.$z, b.$z, a.$w, b.$w)
}
pub fn shuffle_lo_hi_0101(a: Self, b: Self) -> Self {
Self::new(a.$x, a.$y, b.$x, b.$y)
}
pub fn shuffle_hi_lo_2323(a: Self, b: Self) -> Self {
Self::new(b.$z, b.$w, a.$z, a.$w)
}
pub fn shuffled_0022(self) -> Self where T: Copy {
Self::new(self.$x, self.$x, self.$z, self.$z)
}
pub fn shuffled_1133(self) -> Self where T: Copy {
Self::new(self.$y, self.$y, self.$w, self.$w)
}
}
};
}
macro_rules! vec_impl_mat2_via_vec4 {
($Vec:ident) => {
impl<T: Copy + Add<T,Output=T> + Mul<T,Output=T> + Sub<T,Output=T>> $Vec<T> {
pub fn mat2_rows_mul(self, rhs: Self) -> Self {
self * rhs.shuffled((0,3,0,3)) + self.shuffled((1,0,3,2)) * rhs.shuffled((2,1,2,1))
}
pub fn mat2_rows_adj_mul(self, rhs: Self) -> Self {
self.shuffled((3,3,0,0)) * rhs - self.shuffled((1,1,2,2)) * rhs.shuffled((2,3,0,1))
}
pub fn mat2_rows_mul_adj(self, rhs: Self) -> Self {
self * rhs.shuffled((3,0,3,0)) - self.shuffled((1,0,3,2)) * rhs.shuffled((2,1,2,1))
}
pub fn mat2_cols_mul(self, rhs: Self) -> Self {
self * rhs.shuffled((0,0,3,3)) + self.shuffled((2,3,0,1)) * rhs.shuffled((1,1,2,2))
}
pub fn mat2_cols_adj_mul(self, rhs: Self) -> Self {
self.shuffled((3,0,3,0)) * rhs - self.shuffled((2,1,2,1)) * rhs.shuffled((1,0,3,2))
}
pub fn mat2_cols_mul_adj(self, rhs: Self) -> Self {
self * rhs.shuffled((3,3,0,0)) - self.shuffled((2,3,0,1)) * rhs.shuffled((1,1,2,2))
}
}
};
}
macro_rules! vec_impl_from_smaller_vec_and_scalar {
($Vec:ident, $SmallerVec:ident, ($($smaller_vec_get:ident)+)) => {
impl<T> From<($SmallerVec<T>, T)> for $Vec<T> {
fn from(t: ($SmallerVec<T>, T)) -> Self {
Self::new($(t.0.$smaller_vec_get),+, t.1)
}
}
};
}
macro_rules! vec_impl_mint {
($Vec:ident, $mintVec:ident, ($($namedget:ident)+)) => {
#[cfg(feature = "mint")]
impl<T> From<mint::$mintVec<T>> for $Vec<T> {
fn from(v: mint::$mintVec<T>) -> Self {
Self { $($namedget : v.$namedget),+ }
}
}
#[cfg(feature = "mint")]
impl<T> Into<mint::$mintVec<T>> for $Vec<T> {
fn into(self) -> mint::$mintVec<T> {
mint::$mintVec { $($namedget : self.$namedget),+ }
}
}
};
}
macro_rules! vec_impl_all_vecs {
($c_or_simd:ident #[$repr_for_power_of_two_length:meta] $c_or_simd_non_power_of_two:ident #[$repr_for_non_power_of_two_length:meta] $repr_c_non_power_of_two:ident) => {
pub mod vec2 {
use super::*;
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_power_of_two_length]
pub struct Vec2<T> { pub x:T, pub y:T }
vec_impl_vec!($c_or_simd repr_c struct Vec2 vec2 (2) ("({...}, {...})") ("") (x y) (x y) (0 1) (T,T));
vec_impl_mint!(Vec2, Vector2, (x y));
vec_impl_mint!(Vec2, Point2, (x y));
vec_impl_spatial!(Vec2);
vec_impl_spatial_2d!(Vec2);
impl<T> Vec2<T> {
pub fn yx(self) -> Self {
let Self { x, y } = self;
Self { x: y, y: x }
}
pub fn with_x(mut self, x: T) -> Self {
self.x = x;
self
}
pub fn with_y(mut self, y: T) -> Self {
self.y = y;
self
}
pub fn with_z(self, z: T) -> Vec3<T> {
Vec3::new(self.x, self.y, z)
}
pub fn with_w(self, w: T) -> Vec4<T> where T: Zero {
Vec4::new(self.x, self.y, T::zero(), w)
}
}
impl<T> From<Vec3<T>> for Vec2<T> {
fn from(v: Vec3<T>) -> Self {
Self::new(v.x, v.y)
}
}
impl<T> From<Vec4<T>> for Vec2<T> {
fn from(v: Vec4<T>) -> Self {
Self::new(v.x, v.y)
}
}
impl<T> From<Extent2<T>> for Vec2<T> {
fn from(v: Extent2<T>) -> Self {
Self::new(v.w, v.h)
}
}
}
pub use self::vec2::Vec2;
pub mod vec3 {
use super::*;
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_non_power_of_two_length]
pub struct Vec3<T> { pub x:T, pub y:T, pub z:T }
vec_impl_vec!($c_or_simd_non_power_of_two $repr_c_non_power_of_two struct Vec3 vec3 (3) ("({...}, {...}, {...})") ("") (x y z) (x y z) (0 1 2) (T,T,T));
vec_impl_from_smaller_vec_and_scalar!(Vec3, Vec2, (x y));
vec_impl_mint!(Vec3, Vector3, (x y z));
vec_impl_mint!(Vec3, Point3, (x y z));
vec_impl_spatial!(Vec3);
vec_impl_spatial_3d!(Vec3);
impl<T> Vec3<T> {
pub fn zyx(self) -> Self {
let Self { x, y, z } = self;
Self { x: z, y, z: x }
}
pub fn xy(self) -> Vec2<T> {
self.into()
}
pub fn with_x(mut self, x: T) -> Self {
self.x = x;
self
}
pub fn with_y(mut self, y: T) -> Self {
self.y = y;
self
}
pub fn with_z(mut self, z: T) -> Self {
self.z = z;
self
}
pub fn with_w(self, w: T) -> Vec4<T> {
Vec4::new(self.x, self.y, self.z, w)
}
}
impl<T: Zero> From<Vec2<T>> for Vec3<T> {
fn from(v: Vec2<T>) -> Self {
Self::new(v.x, v.y, T::zero())
}
}
impl<T> From<Vec4<T>> for Vec3<T> {
fn from(v: Vec4<T>) -> Self {
Self::new(v.x, v.y, v.z)
}
}
impl<T> From<Extent3<T>> for Vec3<T> {
fn from(v: Extent3<T>) -> Self {
Self::new(v.w, v.h, v.d)
}
}
#[cfg(feature="rgb")]
impl<T> From<Rgb<T>> for Vec3<T> {
fn from(v: Rgb<T>) -> Self {
Self::new(v.r, v.g, v.b)
}
}
#[cfg(feature="uvw")]
impl<T> From<Uvw<T>> for Vec3<T> {
fn from(v: Uvw<T>) -> Self {
Self::new(v.u, v.v, v.w)
}
}
}
pub use self::vec3::Vec3;
pub mod vec4 {
use super::*;
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_power_of_two_length]
pub struct Vec4<T> {
pub x:T, pub y:T, pub z:T,
pub w: T
}
vec_impl_vec!($c_or_simd repr_c struct Vec4 vec4 (4) ("({...}, {...}, {...}, {...})") ("") (x y z w) (x y z w) (0 1 2 3) (T,T,T,T));
vec_impl_from_smaller_vec_and_scalar!(Vec4, Vec3, (x y z));
vec_impl_mint!(Vec4, Vector4, (x y z w));
vec_impl_spatial!(Vec4);
vec_impl_spatial_4d!(Vec4);
vec_impl_shuffle_4d!(Vec4 (x y z w));
vec_impl_mat2_via_vec4!(Vec4);
impl<T> Vec4<T> {
pub fn wxyz(self) -> Self {
let Self { x, y, z, w } = self;
Self { x: w, y: x, z: y, w: z }
}
pub fn wzyx(self) -> Self {
let Self { x, y, z, w } = self;
Self { x: w, y: z, z: y, w: x }
}
pub fn zyxw(self) -> Self {
let Self { x, y, z, w } = self;
Self { x: z, y, z: x, w }
}
pub fn xyz(self) -> Vec3<T> {
self.into()
}
pub fn xy(self) -> Vec2<T> {
self.into()
}
pub fn with_x(mut self, x: T) -> Self {
self.x = x;
self
}
pub fn with_y(mut self, y: T) -> Self {
self.y = y;
self
}
pub fn with_z(mut self, z: T) -> Self {
self.z = z;
self
}
pub fn with_w(mut self, w: T) -> Self {
self.w = w;
self
}
}
impl<T: Zero> From<Vec3<T>> for Vec4<T> {
fn from(v: Vec3<T>) -> Self {
Self::new(v.x, v.y, v.z, T::zero())
}
}
impl<T: Zero> From<Vec2<T>> for Vec4<T> {
fn from(v: Vec2<T>) -> Self {
Self::new(v.x, v.y, T::zero(), T::zero())
}
}
#[cfg(feature="rgba")]
impl<T> From<Rgba<T>> for Vec4<T> {
fn from(v: Rgba<T>) -> Self {
Self::new(v.r, v.g, v.b, v.a)
}
}
}
pub use self::vec4::Vec4;
#[cfg(feature="vec8")]
pub mod vec8 {
use super::*;
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_power_of_two_length]
pub struct Vec8<T>(pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T);
vec_impl_vec!($c_or_simd repr_c tuple Vec8 vec8 (8) ("({...}, {...}, {...}, {...}, {...}, {...}, {...}, {...})") ("") (0 1 2 3 4 5 6 7) (m0 m1 m2 m3 m4 m5 m6 m7) (0 1 2 3 4 5 6 7) (T,T,T,T,T,T,T,T));
vec_impl_spatial!(Vec8);
}
#[cfg(feature="vec8")]
pub use self::vec8::Vec8;
#[cfg(feature="vec16")]
pub mod vec16 {
use super::*;
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_power_of_two_length]
pub struct Vec16<T>(pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T);
vec_impl_vec!($c_or_simd repr_c tuple Vec16 vec16 (16) ("({...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...})") ("") (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) (m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12 m13 m14 m15) (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15) (T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T));
vec_impl_spatial!(Vec16);
}
#[cfg(feature="vec16")]
pub use self::vec16::Vec16;
#[cfg(feature="vec32")]
pub mod vec32 {
use super::*;
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_power_of_two_length]
pub struct Vec32<T>(pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T);
vec_impl_vec!($c_or_simd repr_c tuple Vec32 vec32 (32) ("({...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...})") ("") (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31) (m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12 m13 m14 m15 m16 m17 m18 m19 m20 m21 m22 m23 m24 m25 m26 m27 m28 m29 m30 m31) (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31) (T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T));
vec_impl_spatial!(Vec32);
}
#[cfg(feature="vec32")]
pub use self::vec32::Vec32;
#[cfg(feature="vec64")]
pub mod vec64 {
use super::*;
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_power_of_two_length]
pub struct Vec64<T>(pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T, pub T);
vec_impl_vec!($c_or_simd repr_c tuple Vec64 vec64 (64) ("({...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...}, {...})") ("") (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63) (m0 m1 m2 m3 m4 m5 m6 m7 m8 m9 m10 m11 m12 m13 m14 m15 m16 m17 m18 m19 m20 m21 m22 m23 m24 m25 m26 m27 m28 m29 m30 m31 m32 m33 m34 m35 m36 m37 m38 m39 m40 m41 m42 m43 m44 m45 m46 m47 m48 m49 m50 m51 m52 m53 m54 m55 m56 m57 m58 m59 m60 m61 m62 m63) (0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63) (T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T,T));
vec_impl_spatial!(Vec64);
}
#[cfg(feature="vec64")]
pub use self::vec64::Vec64;
pub mod extent3 {
use super::*;
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_non_power_of_two_length]
pub struct Extent3<T> { pub w:T, pub h:T, pub d:T }
vec_impl_vec!($c_or_simd_non_power_of_two $repr_c_non_power_of_two struct Extent3 extent3 (3) ("({...}, {...}, {...})") ("") (w h d) (w h d) (0 1 2) (T,T,T));
vec_impl_from_smaller_vec_and_scalar!(Extent3, Extent2, (w h));
vec_impl_spatial!(Extent3);
impl<T> From<Vec3<T>> for Extent3<T> {
fn from(v: Vec3<T>) -> Self {
Self::new(v.x, v.y, v.z)
}
}
}
pub use self::extent3::Extent3;
pub mod extent2 {
use super::*;
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_power_of_two_length]
pub struct Extent2<T> { pub w:T, pub h:T }
vec_impl_vec!($c_or_simd repr_c struct Extent2 extent2 (2) ("({...}, {...})") ("") (w h) (w h) (0 1) (T,T));
vec_impl_spatial!(Extent2);
impl<T> From<Vec2<T>> for Extent2<T> {
fn from(v: Vec2<T>) -> Self {
Self::new(v.x, v.y)
}
}
}
pub use self::extent2::Extent2;
#[cfg(feature="rgba")]
pub mod rgba {
use super::*;
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_power_of_two_length]
pub struct Rgba<T> { pub r:T, pub g:T, pub b:T, pub a:T }
vec_impl_vec!($c_or_simd repr_c struct Rgba rgba (4) ("rgba({...}, {...}, {...}, {...})") ("rgba") (r g b a) (r g b a) (0 1 2 3) (T,T,T,T));
vec_impl_color_rgba!{Rgba}
vec_impl_shuffle_4d!(Rgba (r g b a));
#[cfg(feature="rgb")]
vec_impl_from_smaller_vec_and_scalar!(Rgba, Rgb, (r g b));
#[cfg(feature="rgb")]
impl<T> Rgba<T> {
pub fn rgb(self) -> Rgb<T> {
self.into()
}
}
impl<T> From<Vec4<T>> for Rgba<T> {
fn from(v: Vec4<T>) -> Self {
Self::new(v.x, v.y, v.z, v.w)
}
}
#[cfg(feature="rgb")]
impl<T: ColorComponent> From<Rgb<T>> for Rgba<T> {
fn from(v: Rgb<T>) -> Self {
Self::from_opaque(v)
}
}
}
#[cfg(feature="rgba")]
pub use self::rgba::Rgba;
#[cfg(feature="rgb")]
pub mod rgb {
use super::*;
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_non_power_of_two_length]
pub struct Rgb<T> { pub r:T, pub g:T, pub b:T }
vec_impl_vec!($c_or_simd_non_power_of_two $repr_c_non_power_of_two struct Rgb rgb (3) ("rgb({...}, {...}, {...})") ("rgb") (r g b) (r g b) (0 1 2) (T,T,T));
vec_impl_color_rgb!{Rgb}
impl<T> From<Vec3<T>> for Rgb<T> {
fn from(v: Vec3<T>) -> Self {
Self::new(v.x, v.y, v.z)
}
}
#[cfg(feature="rgba")]
impl<T> From<Rgba<T>> for Rgb<T> {
fn from(v: Rgba<T>) -> Self {
Self::new(v.r, v.g, v.b)
}
}
}
#[cfg(feature="rgb")]
pub use self::rgb::Rgb;
#[cfg(feature="uvw")]
pub mod uvw {
use super::*;
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_non_power_of_two_length]
pub struct Uvw<T> { pub u:T, pub v:T, pub w:T }
vec_impl_vec!($c_or_simd_non_power_of_two $repr_c_non_power_of_two struct Uvw uvw (3) ("({...}, {...}, {...})") ("") (u v w) (u v w) (0 1 2) (T,T,T));
#[cfg(feature="uv")]
vec_impl_from_smaller_vec_and_scalar!(Uvw, Uv, (u v));
impl<T> From<Vec3<T>> for Uvw<T> {
fn from(v: Vec3<T>) -> Self {
Self::new(v.x, v.y, v.z)
}
}
}
#[cfg(feature="uvw")]
pub use self::uvw::Uvw;
#[cfg(feature="uv")]
pub mod uv {
use super::*;
#[allow(missing_docs)]
#[derive(Debug, Default, Clone, Copy, Hash, Eq, PartialEq)]
#[cfg_attr(feature="serde", derive(Serialize, Deserialize))]
#[$repr_for_power_of_two_length]
pub struct Uv<T> { pub u:T, pub v:T }
vec_impl_vec!($c_or_simd repr_c struct Uv uv (2) ("({...}, {...})") ("") (u v) (u v) (0 1) (T,T));
impl<T> From<Vec2<T>> for Uv<T> {
fn from(v: Vec2<T>) -> Self {
Self::new(v.x, v.y)
}
}
}
#[cfg(feature="uv")]
pub use self::uv::Uv;
}
}
pub mod repr_c {
use super::*;
vec_impl_all_vecs!{c #[repr(C)] c #[repr(C)] repr_c}
}
#[cfg(all(nightly, feature="repr_simd"))]
pub mod repr_simd {
use super::*;
vec_impl_all_vecs!{simd #[repr(simd)] c #[repr(C)] repr_simd}
}
pub use self::repr_c::*;
#[cfg(test)]
mod tests {
macro_rules! test_vec_t {
(repr_c $Vec:ident<$T:ident>) => {
test_vec_t!{common $Vec<$T>}
use $crate::vtest::Rc;
#[test]
fn from_rc_array() {
let v: $Vec<Rc<i32>> = Default::default();
let mut a = v.into_array();
assert_eq!(Rc::strong_count(&a[0]), 1);
*Rc::make_mut(&mut a[0]) = 2;
let mut v = $Vec::from(a);
assert_eq!(Rc::strong_count(&v[0]), 1);
*Rc::make_mut(&mut v[0]) = 1;
}
#[test]
fn vec_rc_into_iter() {
let v: $Vec<Rc<i32>> = Default::default();
let mut rc = v.into_iter().next().unwrap();
assert_eq!(Rc::strong_count(&rc), 1);
*Rc::make_mut(&mut rc) = 1;
}
};
(repr_simd $Vec:ident<$T:ident>) => {
test_vec_t!{common $Vec<$T>}
};
(common $Vec:ident<$T:ident>) => {
#[test] fn iterator_api() {
let v = $Vec::<i32>::default();
let mut v: $Vec<i32> = (0..).into_iter().take(v.elem_count()).collect();
for _ in &mut v {}
for _ in &v {}
for _ in v {}
let mut v = $Vec::<i32>::default();
let _ = v.as_ptr();
let _ = v.as_mut_ptr();
let _ = v.iter_mut();
let _ = v.iter();
let _ = v.into_iter();
let mut v = $Vec::<i32>::default();
let _ = v.iter_mut().rev();
let _ = v.iter().rev();
let _ = v.into_iter().rev();
let mut v = $Vec::<i32>::default();
let _ = v[0];
v[0] = 0;
let _ = v.get(0);
let _ = v.get_mut(0);
unsafe {
let _ = v.get_unchecked(0);
let _ = v.get_unchecked_mut(0);
}
}
};
(repr_simd_except_bool $Vec:ident<$T:ident>) => {
#[test] fn is_actually_packed() {
let v = $Vec::<$T>::iota();
let a = v.clone().into_array();
assert_eq!(v.as_slice(), &a);
}
};
(repr_c_except_bool $Vec:ident<$T:ident>) => {
#[test] fn is_actually_packed() {
let v = $Vec::<$T>::iota();
let a = v.clone().into_array();
assert_eq!(v.as_slice(), &a);
}
#[test] fn is_actually_packed_refcell() {
let v = $Vec::<$T>::iota().map(::std::cell::RefCell::new);
let a = v.clone().into_array();
assert_eq!(v.as_slice(), &a);
}
#[test] fn commutative() {
let v = $Vec::from(5 as $T);
assert_eq!((2 as $T) * v, v * (2 as $T));
assert_eq!((2 as $T) + v, v + (2 as $T));
}
};
}
macro_rules! for_each_type {
($vec:ident $Vec:ident $($T:ident)+) => {
mod $vec {
mod repr_c {
use $crate::vec::repr_c::$Vec;
$(mod $T {
use super::$Vec;
test_vec_t!{repr_c $Vec<$T>}
test_vec_t!{repr_c_except_bool $Vec<$T>}
})+
mod bool {
use super::$Vec;
test_vec_t!{repr_c $Vec<bool>}
}
}
#[cfg(all(nightly, feature="repr_simd"))]
mod repr_simd {
$(mod $T {
use $crate::vec::repr_simd::$Vec;
test_vec_t!{repr_simd $Vec<$T>}
test_vec_t!{repr_simd_except_bool $Vec<$T>}
})+
mod bool {
use $crate::vec::repr_simd::$Vec;
test_vec_t!{repr_simd $Vec<bool>}
}
}
}
};
}
for_each_type!{vec2 Vec2 i8 u8 i16 u16 i32 u32 i64 u64 f32 f64}
for_each_type!{vec3 Vec3 i8 u8 i16 u16 i32 u32 i64 u64 f32 f64}
for_each_type!{vec4 Vec4 i8 u8 i16 u16 i32 u32 i64 u64 f32 f64}
#[cfg(feature="vec8")] for_each_type!{vec8 Vec8 i8 u8 i16 u16 i32 u32 i64 u64 f32 f64}
#[cfg(feature="vec16")] for_each_type!{vec16 Vec16 i8 u8 i16 u16 i32 u32 i64 u64 f32 f64}
#[cfg(feature="vec32")] for_each_type!{vec32 Vec32 i8 u8 i16 u16 i32 u32 i64 u64 f32 f64}
#[cfg(feature="rgba")] for_each_type!{rgba Rgba i8 u8 i16 u16 i32 u32 i64 u64 f32 f64}
#[cfg(feature="rgb")] for_each_type!{rgb Rgb i8 u8 i16 u16 i32 u32 i64 u64 f32 f64}
for_each_type!{extent3 Extent3 i8 u8 i16 u16 i32 u32 i64 u64 f32 f64}
for_each_type!{extent2 Extent2 i8 u8 i16 u16 i32 u32 i64 u64 f32 f64}
#[cfg(feature="uv")] for_each_type!{uv Uv i8 u8 i16 u16 i32 u32 i64 u64 f32 f64}
#[cfg(feature="uvw")] for_each_type!{uvw Uvw i8 u8 i16 u16 i32 u32 i64 u64 f32 f64}
}