use crate::lt_list::{Lt1, LtList};
use crate::tag::{ReifySized, TagTypeId};
use crate::want::{ErasedWantFor, Want, WantOne};
pub trait Request<L: LtList> {
type Want: Want<L> + Default;
type Output;
fn into_output(want: Self::Want) -> Self::Output;
}
impl<L: LtList, T: ReifySized<L>> Request<L> for T {
type Want = WantOne<L, T::UsedTag>;
type Output = Option<T::Reified>;
fn into_output(want: Self::Want) -> Self::Output {
want.into_inner()
}
}
macro_rules! impl_reqx {
($name:ident: $($type:ident),*) => {
#[derive(Default, Debug)]
pub struct $name<$($type),*>($(pub $type),*);
impl<'r, L: LtList $(, $type)*> Request<Lt1<'r, L>> for $name<$($type),*>
where
$($type: Request<Lt1<'r, L>>,)*
{
type Want = $name<$($type::Want),*>;
type Output = $name<$($type::Output),*>;
#[allow(non_snake_case)]
fn into_output(want: Self::Want) -> Self::Output {
let $name($($type),*) = want;
$name($($type::into_output($type)),*)
}
}
impl<$($type),*> Request<$crate::lt_list::Nil> for $name<$($type),*>
where
$($type: Request<$crate::lt_list::Nil>,)*
{
type Want = $name<$($type::Want),*>;
type Output = $name<$($type::Output),*>;
#[allow(non_snake_case)]
fn into_output(want: Self::Want) -> Self::Output {
let $name($($type),*) = want;
$name($($type::into_output($type)),*)
}
}
impl<L: LtList $(, $type)*> Want<L> for $name<$($type),*>
where
$($type: Want<L>,)*
{
#[allow(non_snake_case)]
fn try_for_id(
&mut self,
tag_type_id: 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);