use ty_tag::lifetime_list::LifetimeList;
use super::{Request, Want};
use crate::want::ErasedWantFor;
macro_rules! impl_reqx {
($name:ident: $($type:ident),*) => {
#[derive(Default, Debug)]
pub struct $name<$($type),*>($($type),*);
impl<L: LifetimeList $(, $type)*> Request<L> for $name<$($type),*>
where
$($type: Request<L>,)*
{
type Want = $name<$($type::Want),*>;
type Output = ($($type::Output),*);
#[allow(non_snake_case)]
fn into_output(want: Self::Want) -> Self::Output {
let $name($($type),*) = want;
($($type::into_output($type)),*)
}
}
impl<L: LifetimeList $(, $type)*> Want<L> for $name<$($type),*>
where
$($type: Want<L>,)*
{
#[allow(non_snake_case)]
fn try_for_id(
&mut self,
tag_type_id: ty_tag::TagTypeId<L>,
) -> Option<ErasedWantFor<'_, L>> {
let $name($($type),*) = self;
$(if !$type.is_satisfied() {
if let Some(want) = $type.try_for_id(tag_type_id) {
return Some(want);
}
})*
None
}
#[allow(non_snake_case)]
fn is_satisfied(&self) -> bool {
let $name($($type),*) = self;
$($type.is_satisfied())&&*
}
}
};
}
pub trait Optional: optional_seal::Sealed {
type Value;
fn into_option(self) -> Option<Self::Value>;
}
impl<T> Optional for Option<T> {
type Value = T;
fn into_option(self) -> Option<Self::Value> {
self
}
}
mod optional_seal {
pub trait Sealed {}
impl<T> Sealed for Option<T> {}
}
macro_rules! impl_reqx_all {
($name:ident: $($type:ident),*) => {
#[derive(Default, Debug)]
pub struct $name<$($type),*>($($type),*);
impl<L: LifetimeList $(, $type)*> Request<L> for $name<$($type),*>
where
$($type: Request<L>,)*
$($type::Output: Optional,)*
{
type Want = $name<$($type::Want),*>;
type Output = Option<($(<$type::Output as Optional>::Value),*)>;
#[allow(non_snake_case)]
fn into_output(want: Self::Want) -> Self::Output {
let $name($($type),*) = want;
$(
let $type = $type::into_output($type).into_option();
)*
if let ($(Some($type)),*) = ($($type),*) {
Some(($($type),*))
} else {
None
}
}
}
impl<L: LifetimeList $(, $type)*> Want<L> for $name<$($type),*>
where
$($type: Want<L>,)*
{
#[allow(non_snake_case)]
fn try_for_id(
&mut self,
tag_type_id: ty_tag::TagTypeId<L>,
) -> Option<ErasedWantFor<'_, L>> {
let $name($($type),*) = self;
$(if !$type.is_satisfied() {
if let Some(want) = $type.try_for_id(tag_type_id) {
return Some(want);
}
})*
None
}
#[allow(non_snake_case)]
fn is_satisfied(&self) -> bool {
let $name($($type),*) = self;
$($type.is_satisfied())&&*
}
}
};
}
impl_reqx!(Req2: T0, T1);
impl_reqx!(Req3: T0, T1, T2);
impl_reqx!(Req4: T0, T1, T2, T3);
impl_reqx!(Req5: T0, T1, T2, T3, T4);
impl_reqx!(Req6: T0, T1, T2, T3, T4, T5);
impl_reqx_all!(ReqAll2: T0, T1);
impl_reqx_all!(ReqAll3: T0, T1, T2);
impl_reqx_all!(ReqAll4: T0, T1, T2, T3);
impl_reqx_all!(ReqAll5: T0, T1, T2, T3, T4);
impl_reqx_all!(ReqAll6: T0, T1, T2, T3, T4, T5);