use std::marker::PhantomData;
use crate::nest::{TupleNest, TupleUnnest};
use crate::{TypeMap, TypePair, EOT};
#[doc(hidden)]
pub trait TupleFiltered {
type Input;
type Output;
}
impl<H1, T1, T2> TupleFiltered for TypePair<(H1, T1), (TupleFilterExclude, T2)>
where
TypePair<T1, T2>: TupleFiltered,
{
type Input = (H1, T1);
type Output = <TypePair<T1, T2> as TupleFiltered>::Output;
}
impl<H1, T1, T2> TupleFiltered for TypePair<(H1, T1), (TupleFilterInclude, T2)>
where
TypePair<T1, T2>: TupleFiltered,
{
type Input = (H1, T1);
type Output = (H1, <TypePair<T1, T2> as TupleFiltered>::Output);
}
impl TupleFiltered for TypePair<EOT, EOT> {
type Output = EOT;
type Input = EOT;
}
#[doc(hidden)]
pub trait TupleFilteredValue<I> {
type Output;
fn filter(input: I) -> Self::Output;
}
impl<H1, T1, T2> TupleFilteredValue<(H1, T1)> for TypePair<(H1, T1), (TupleFilterInclude, T2)>
where
TypePair<T1, T2>: TupleFilteredValue<T1>,
{
type Output = (H1, <TypePair<T1, T2> as TupleFilteredValue<T1>>::Output);
fn filter(input: (H1, T1)) -> Self::Output {
(
input.0,
<TypePair<T1, T2> as TupleFilteredValue<T1>>::filter(input.1),
)
}
}
impl<H1, T1, T2> TupleFilteredValue<(H1, T1)> for TypePair<(H1, T1), (TupleFilterExclude, T2)>
where
TypePair<T1, T2>: TupleFilteredValue<T1>,
{
type Output = <TypePair<T1, T2> as TupleFilteredValue<T1>>::Output;
fn filter(input: (H1, T1)) -> Self::Output {
<TypePair<T1, T2> as TupleFilteredValue<T1>>::filter(input.1)
}
}
impl TupleFilteredValue<EOT> for TypePair<EOT, EOT> {
type Output = EOT;
fn filter(_: EOT) -> Self::Output {
EOT
}
}
#[doc(hidden)]
pub trait TupleFilterer<TUPLE> {
type Output;
fn do_filter(&self, tuple: TUPLE) -> Self::Output;
}
#[doc(hidden)]
pub struct TupleFilter<T, P>(PhantomData<(T, P)>);
impl<T, P> TupleFilter<T, P> {
pub fn of() -> Self {
Self(PhantomData)
}
pub fn of_ref(_: &T) -> Self {
Self(PhantomData)
}
}
type Filterer<TUPLE, PREDICATE> = TypePair<
<TUPLE as TupleNest>::Nested,
<<TUPLE as TupleNest>::Nested as TypeMap<PREDICATE>>::Mapped,
>;
impl<TUPLE, PREDICATE> TupleFilterer<TUPLE> for TupleFilter<TUPLE, PREDICATE>
where
TUPLE: TupleNest,
<TUPLE as TupleNest>::Nested: TypeMap<PREDICATE>,
Filterer<TUPLE, PREDICATE>: TupleFilteredValue<<TUPLE as TupleNest>::Nested>,
<Filterer<TUPLE, PREDICATE> as TupleFilteredValue<<TUPLE as TupleNest>::Nested>>::Output:
TupleUnnest,
{
type Output = <<Filterer<TUPLE, PREDICATE> as TupleFilteredValue<
<TUPLE as TupleNest>::Nested,
>>::Output as TupleUnnest>::Unnested;
fn do_filter(&self, tuple: TUPLE) -> Self::Output {
let nested = tuple.nest();
<Filterer<TUPLE, PREDICATE> as TupleFilteredValue<<TUPLE as TupleNest>::Nested>>::filter(
nested,
)
.unnest()
}
}
#[macro_export]
macro_rules! tuple_filter_predicate {
($vis:vis $predicate:ident = {
include = ($($(~ <$($ilt:lifetime),* $(,)? $($igen:ident $($igen2:ident)? $(: $($ibound:path)+)?),*>)? $include:ty),*),
exclude = ($($(~ <$($elt:lifetime),* $(,)? $($egen:ident $($egen2:ident)? $(: $($ebound:path)+)?),*>)? $exclude:ty),*)
}) => {
$vis struct $predicate {}
$(
impl $(<$($ilt,)* $($igen $($igen2)? $(: $($ibound)+)?,)*>)? $crate::TypeMap<$predicate> for $include {
type Mapped = $crate::TupleFilterInclude;
}
)*
$(
impl $(<$($elt,)* $($egen $($egen2)? $(: $($ebound)+)?,)*>)? $crate::TypeMap<$predicate> for $exclude {
type Mapped = $crate::TupleFilterExclude;
}
)*
};
}
#[macro_export]
macro_rules! tuple_filter {
($predicate:ident::filter_type($ty:ty)) => {
<<$crate::TypePair<
<$ty as $crate::TupleNest>::Nested,
<<$ty as $crate::TupleNest>::Nested as $crate::TypeMap<$predicate>>::Mapped,
> as $crate::__macro_support::TupleFiltered>::Output as $crate::TupleUnnest>::Unnested
};
($predicate:ident::filter($tuple:expr)) => {{
use $crate::__macro_support::TupleFilterer;
let tuple = $tuple;
$crate::__macro_support::TupleFilter::<_, P>::of_ref(&tuple).do_filter(tuple)
}};
}
#[derive(Default)]
pub struct TupleFilterInclude();
#[derive(Default)]
pub struct TupleFilterExclude();