use crate::index::{IndexList, UniqueIndexList};
use crate::internal::Sealed;
use paradis_core::Bounds;
pub struct IndexFlatten<SourceIndices>(pub(crate) SourceIndices);
unsafe impl<SourceIndices> IndexList for IndexFlatten<SourceIndices>
where
SourceIndices: IndexList,
SourceIndices::Index: Flatten,
<SourceIndices::Index as Flatten>::Flattened: Copy,
{
type Index = <SourceIndices::Index as Flatten>::Flattened;
const ALWAYS_BOUNDED: bool = SourceIndices::ALWAYS_BOUNDED;
unsafe fn get_index_unchecked(&self, loc: usize) -> Self::Index {
unsafe { self.0.get_index_unchecked(loc) }.flatten()
}
fn num_indices(&self) -> usize {
self.0.num_indices()
}
fn bounds(&self) -> Option<Bounds<Self::Index>> {
self.0.bounds().map(|bounds| Bounds {
offset: bounds.offset.flatten(),
extent: bounds.extent.flatten(),
})
}
}
unsafe impl<SourceIndices> UniqueIndexList for IndexFlatten<SourceIndices>
where
SourceIndices: UniqueIndexList,
SourceIndices::Index: Flatten,
<SourceIndices::Index as Flatten>::Flattened: Copy,
{
}
pub trait Concatenate<T>: Sealed {
type Concatenated;
fn concatenate(self, other: T) -> Self::Concatenated;
}
pub type Concatenated<A, B> = <A as Concatenate<B>>::Concatenated;
pub trait Flatten: Sealed {
type Flattened;
fn flatten(self) -> Self::Flattened;
}
macro_rules! var_type {
($single_name:ident) => { usize };
(($($tuple_elem:ident),+)) => { ($(var_type!(to_type($tuple_elem))),+) };
(to_type($var:ident)) => { usize }
}
macro_rules! impl_usize_concatenate {
($left_var:tt + $right_var:tt => $result_var:tt) => {
impl Concatenate<var_type!($right_var)> for var_type!($left_var) {
type Concatenated = var_type!($result_var);
fn concatenate(self, $right_var: var_type!($right_var)) -> Self::Concatenated {
let $left_var = self;
$result_var
}
}
};
}
impl_usize_concatenate!(a + b => (a, b));
impl_usize_concatenate!(a + (b, c) => (a, b, c));
impl_usize_concatenate!(a + (b, c, d) => (a, b, c, d));
impl_usize_concatenate!(a + (b, c, d, e) => (a, b, c, d, e));
impl_usize_concatenate!((a, b) + c => (a, b, c));
impl_usize_concatenate!((a, b) + (c, d) => (a, b, c, d));
impl_usize_concatenate!((a, b) + (c, d, e) => (a, b, c, d, e));
impl_usize_concatenate!((a, b, c) + d => (a, b, c, d));
impl_usize_concatenate!((a, b, c) + (d, e) => (a, b, c, d, e));
impl_usize_concatenate!((a, b, c, d) + e => (a, b, c, d, e));
impl Flatten for usize {
type Flattened = Self;
fn flatten(self) -> Self {
self
}
}
impl<A: Flatten> Flatten for (A,) {
type Flattened = (A::Flattened,);
fn flatten(self) -> Self::Flattened {
(self.0.flatten(),)
}
}
impl<A: Flatten, B: Flatten> Flatten for (A, B)
where
A::Flattened: Concatenate<B::Flattened>,
{
type Flattened = Concatenated<A::Flattened, B::Flattened>;
fn flatten(self) -> Self::Flattened {
self.0.flatten().concatenate(self.1.flatten())
}
}
impl<A: Flatten, B: Flatten, C: Flatten> Flatten for (A, B, C)
where
(A, B): Flatten,
<(A, B) as Flatten>::Flattened: Concatenate<C::Flattened>,
{
type Flattened = Concatenated<<(A, B) as Flatten>::Flattened, C::Flattened>;
fn flatten(self) -> Self::Flattened {
(self.0, self.1).flatten().concatenate(self.2.flatten())
}
}
impl<A: Flatten, B: Flatten, C: Flatten, D: Flatten> Flatten for (A, B, C, D)
where
(A, B, C): Flatten,
<(A, B, C) as Flatten>::Flattened: Concatenate<D::Flattened>,
{
type Flattened = Concatenated<<(A, B, C) as Flatten>::Flattened, D::Flattened>;
fn flatten(self) -> Self::Flattened {
(self.0, self.1, self.2)
.flatten()
.concatenate(self.3.flatten())
}
}
impl<A: Flatten, B: Flatten, C: Flatten, D: Flatten, E: Flatten> Flatten for (A, B, C, D, E)
where
(A, B, C, D): Flatten,
<(A, B, C, D) as Flatten>::Flattened: Concatenate<E::Flattened>,
{
type Flattened = Concatenated<<(A, B, C, D) as Flatten>::Flattened, E::Flattened>;
fn flatten(self) -> Self::Flattened {
(self.0, self.1, self.2, self.3)
.flatten()
.concatenate(self.4.flatten())
}
}