use crate::tag::{ReifySized, TagTypeId};
use crate::want::{ErasedWantFor, WantOne};
use crate::{Lt1, LtList, Provider, Want};
pub trait RequestExt {
fn request<'r, P>(provider: &'r P) -> Self::Output
where
Self: Request<'r, P::Lifetimes>,
P: ?Sized + Provider,
{
let mut want = Self::Want::default();
provider.provide(&mut want);
Self::into_output(want)
}
fn request_mut<'r, P>(provider: &'r mut P) -> Self::Output
where
Self: Request<'r, P::Lifetimes>,
P: ?Sized + Provider,
{
let mut want = Self::Want::default();
provider.provide_mut(&mut want);
Self::into_output(want)
}
}
pub fn request_from<'r, T, P>(provider: &'r P) -> T::Output
where
T: Request<'r, P::Lifetimes>,
P: ?Sized + Provider,
{
T::request(provider)
}
pub fn request_from_mut<'r, T, P>(provider: &'r mut P) -> T::Output
where
T: Request<'r, P::Lifetimes>,
P: ?Sized + Provider,
{
T::request_mut(provider)
}
impl<T> RequestExt for T {}
pub trait Request<'r, L: LtList> {
type Want: Want<'r, L> + Default;
type Output;
fn into_output(want: Self::Want) -> Self::Output;
}
impl<'r, L: LtList, T: ReifySized<Lt1<'r, L>>> Request<'r, L> for T {
type Want = WantOne<'r, L, T::Tag>;
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<'r, L> for $name<$($type),*>
where
$($type: Request<'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<'r, L: LtList $(, $type)*> Want<'r, L> for $name<$($type),*>
where
$($type: Want<'r, L>,)*
{
#[allow(non_snake_case)]
fn try_for_id(
&mut self,
tag_type_id: TagTypeId<Lt1<'r, L>>,
) -> Option<ErasedWantFor<'_, Lt1<'r, 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);