use core::ops::Add;
use generic_array::{ArrayLength, GenericArray};
use super::GenericVector;
#[macro_export]
macro_rules! const_splat {
(
<$($real_param:ident),+> = <$($gen_param:ident $(: $bound:path)?),+ $(,)?>
$ty:ty : $value:expr
) => {{
use core::marker::PhantomData;
struct __GenericSplatValue<$($gen_param $(: $bound)?),+>(
PhantomData<$($gen_param),+>
);
impl<$($gen_param $(: $bound)?),+> $crate::vector::SplatConst<$ty>
for __GenericSplatValue<$($gen_param),+> {
const VALUE: $ty = const { $value };
}
const { $crate::vector::const_splat::<_,
__GenericSplatValue<$($real_param),+>
>() }
}};
(int <$E:ty>: $n:expr) => {
const { $crate::vector::const_splat::<_, <$E as $crate::register::FloatElement>::ConstInt<{$n}>>() }
};
(ratio <$E:ty>: $n:expr, $d:expr) => {
const { $crate::vector::const_splat::<_, <$E as $crate::register::FloatElement>::ConstRatio<{$n}, {$d}>>() }
};
($ty:ty: $value:expr) => {{
struct __ConstSplatValue;
impl $crate::vector::SplatConst<$ty> for __ConstSplatValue {
const VALUE: $ty = const { $value };
}
const { $crate::vector::const_splat::<_, __ConstSplatValue>() }
}};
(<$ty:ty $(as $trait:path)?>::$associated:ident) => {{
struct __ConstSplatValue;
impl $crate::vector::SplatConst<$ty> for __ConstSplatValue {
const VALUE: $ty = const { <$ty $(as $trait)?>::$associated };
}
const { $crate::vector::const_splat::<_, __ConstSplatValue>() }
}};
}
pub trait AddLength<N: ArrayLength>: ArrayLength {
type Output: ArrayLength;
}
impl<N1, N2> AddLength<N2> for N1
where
N1: ArrayLength + Add<N2>,
N2: ArrayLength,
<N1 as Add<N2>>::Output: ArrayLength,
{
type Output = <N1 as Add<N2>>::Output;
}
pub type Inc<U> = <U as AddLength<generic_array::typenum::U1>>::Output;
#[doc(hidden)]
#[macro_export]
macro_rules! const_new_impl {
($N:ty, [$($x:expr),*], []) => ( $N );
($N:ty, [], [$x1:expr]) => (
$crate::const_new_impl!($crate::vector::splat::Inc<$N>, [$x1], [])
);
($N:ty, [], [$x1:expr, $($x:expr),+]) => (
$crate::const_new_impl!($crate::vector::splat::Inc<$N>, [$x1], [$($x),+])
);
($N:ty, [$($y:expr),+], [$x1:expr]) => (
$crate::const_new_impl!($crate::vector::splat::Inc<$N>, [$($y),+, $x1], [])
);
($N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => (
$crate::const_new_impl!($crate::vector::splat::Inc<$N>, [$($y),+, $x1], [$($x),+])
);
}
#[macro_export]
macro_rules! const_new {
($ty:ty: [$($value:expr),+ $(,)?]) => {{
type N = $crate::const_new_impl!($crate::generic_array::typenum::U0, [], [$($value),+]);
struct __ConstNewValue;
impl $crate::vector::NewConst<$ty, N> for __ConstNewValue {
const VALUES: $crate::generic_array::GenericArray<$ty, N> =
const { $crate::generic_array::GenericArray::from_array([$($value),+]) };
}
const { $crate::vector::const_new::<_, N, __ConstNewValue>() }
}};
(
<$($real_param:ident),+> = <$($gen_param:ident $(: $bound:path)?),+ $(,)?>
<$ty:ty>: [$($value:expr),+ $(,)?]
) => {{
use core::marker::PhantomData;
type N = $crate::const_new_impl!($crate::generic_array::typenum::U0, [], [$($value),+]);
struct __GenericNewValue<$($gen_param $(: $bound)?),+>(
PhantomData<($($gen_param),+)>
);
impl<$($gen_param $(: $bound)?),+> $crate::vector::NewConst<$ty, N>
for __GenericNewValue<$($gen_param),+> {
const VALUES: $crate::generic_array::GenericArray<$ty, N> =
const { $crate::generic_array::GenericArray::from_array([$($value),+]) };
}
const { $crate::vector::const_new::<_, N, __GenericNewValue<$($real_param),+>>() }
}};
}
#[inline(never)]
pub const fn const_splat<V: GenericVector, E: SplatConst<V::Element>>() -> V {
<<V as SplatVector<V::Element>>::Splat<E> as VectorValue<E, V>>::VALUE
}
pub const fn const_new<V: GenericVector<Lanes = N>, N: ArrayLength, C: NewConst<V::Element, N>>() -> V {
<<V as NewVector<V::Element, N>>::New<C> as VectorValue<C, V>>::VALUE
}
pub trait VectorValue<C, V: Sized>: Sized {
const VALUE: V;
}
pub trait SplatConst<E> {
const VALUE: E;
}
pub trait NewConst<E, N: ArrayLength> {
const VALUES: GenericArray<E, N>;
}
pub trait SplatVector<E>: Sized {
type Splat<T: SplatConst<E>>: VectorValue<T, Self>;
}
pub trait NewVector<E, N: ArrayLength>: Sized {
type New<T: NewConst<E, N>>: VectorValue<T, Self>;
}