use core::marker::PhantomData;
use generic_array::{ArrayLength, GenericArray};
use crate::{Vector, register::Register};
#[doc(hidden)]
pub use crate::register::SwizzleIndices;
pub(crate) struct AlignIndices<const OFFSET: usize, N>(PhantomData<N>);
impl<const OFFSET: usize, N: ArrayLength> SwizzleIndices<N> for AlignIndices<OFFSET, N> {
const INDICES: GenericArray<u32, N> = const {
let mut idxs: GenericArray<u32, N> = unsafe { core::mem::zeroed() };
let ptr = &mut idxs as *mut GenericArray<u32, N> as *mut u32;
let mut i = 0;
while i < N::USIZE {
unsafe { *ptr.add(i) = (i + OFFSET) as u32 };
i += 1;
}
idxs
};
}
pub trait Swizzle<N: ArrayLength>: Sized {
fn swizzle(self, other: Self, indices: GenericArray<u32, N>) -> Self;
#[inline(always)]
fn swizzle_const<I: SwizzleIndices<N>>(self, other: Self) -> Self {
Self::swizzle(self, other, I::INDICES)
}
fn permute(self, indices: GenericArray<u32, N>) -> Self;
#[inline(always)]
fn permute_const<I: SwizzleIndices<N>>(self) -> Self {
Self::permute(self, I::INDICES)
}
}
impl<R: Register> Swizzle<R::Lanes> for Vector<R>
where
R: Register,
{
#[inline(always)]
fn swizzle(self, other: Self, indices: GenericArray<u32, R::Lanes>) -> Self {
Vector(R::swizzle(self.0, other.0, indices))
}
#[inline(always)]
fn swizzle_const<I: SwizzleIndices<R::Lanes>>(self, other: Self) -> Self {
Vector(R::swizzle_const::<I>(self.0, other.0))
}
#[inline(always)]
fn permute(self, indices: GenericArray<u32, R::Lanes>) -> Self {
Vector(R::permutev(self.0, indices))
}
#[inline(always)]
fn permute_const<I: SwizzleIndices<R::Lanes>>(self) -> Self {
Vector(R::permutev_const::<I>(self.0))
}
}
#[macro_export]
macro_rules! swizzle {
($a:expr, $b:expr, [$($i:expr),* $(,)?]) => {{
#[inline(always)]
fn __do_swizzle2<N: $crate::generic_array::ArrayLength, S: $crate::swizzle::Swizzle<N>>(a: S, b: S) -> S {
use $crate::{swizzle::{Swizzle, SwizzleIndices}, generic_array::{GenericArray, typenum::Unsigned}};
struct Indices<N: $crate::generic_array::ArrayLength>(core::marker::PhantomData<N>);
impl<N: $crate::generic_array::ArrayLength> SwizzleIndices<N> for Indices<N> {
const INDICES: GenericArray<u32, N> = {
let idxs = [$($i),*];
assert!(N::USIZE == idxs.len(), "Swizzle mask must be the same length of the vector");
unsafe { $crate::generic_array::const_transmute::<_, GenericArray<u32, N>>(idxs) }
};
}
a.swizzle_const::<Indices::<N>>(b)
}
__do_swizzle2($a, $b)
}};
($a:expr, [$($i:expr),* $(,)?]) => {{
#[inline(always)]
fn __do_swizzle1<N: $crate::generic_array::ArrayLength, S: $crate::swizzle::Swizzle<N>>(a: S) -> S {
use $crate::{swizzle::{Swizzle, SwizzleIndices}, generic_array::{GenericArray, typenum::Unsigned}};
struct Indices<N: $crate::generic_array::ArrayLength>(core::marker::PhantomData<N>);
impl<N: $crate::generic_array::ArrayLength> SwizzleIndices<N> for Indices<N> {
const INDICES: GenericArray<u32, N> = const {
let idxs = [$($i),*];
assert!(N::USIZE == idxs.len(), "Swizzle mask must be the same length of the vector");
unsafe { $crate::generic_array::const_transmute::<_, $crate::generic_array::GenericArray<u32, N>>(idxs) }
};
}
a.permute_const::<Indices::<N>>()
}
__do_swizzle1($a)
}};
($a:expr, $b:expr, $idxs:expr) => { $crate::swizzle::Swizzle::swizzle($a, $b, $idxs) };
($a:expr, $idxs:expr) => { $crate::swizzle::Swizzle::permute($a, $idxs) };
}