use frunk_core::hlist::{HCons, HList, HNil};
use super::{AsyncEvaluablePredicate, Predicate, PurePredicate, SyncEvaluablePredicate};
use crate::{BoxError, BoxFuture};
pub trait PredicateList<S>: HList {
fn fmt_joined_label(buf: &mut String, sep: &str);
}
pub trait PurePredicateList<S>: PredicateList<S> {}
pub trait SyncEvaluablePredicateList<S>: PredicateList<S> {
fn evaluate_all_for(sub: &S) -> Result<(), BoxError>;
}
pub trait AsyncEvaluablePredicateList<S>: PredicateList<S> {
fn evaluate_all_for<'s>(sub: &'s S) -> BoxFuture<'s, Result<(), BoxError>>
where
S: 's;
}
impl<S, H, T> PredicateList<S> for HCons<H, T>
where
H: Predicate<S>,
T: PredicateList<S>,
{
fn fmt_joined_label(buf: &mut String, sep: &str) {
buf.push_str(H::label().as_ref());
buf.push_str(sep);
T::fmt_joined_label(buf, sep);
}
}
impl<S, H, T> PurePredicateList<S> for HCons<H, T>
where
H: PurePredicate<S>,
T: PurePredicateList<S>,
{
}
impl<S, H, T> SyncEvaluablePredicateList<S> for HCons<H, T>
where
H: SyncEvaluablePredicate<S>,
T: SyncEvaluablePredicateList<S>,
{
fn evaluate_all_for(sub: &S) -> Result<(), BoxError> {
match H::evaluate_for(sub) {
Ok(_) => T::evaluate_all_for(sub),
Err(e) => Err(e.into()),
}
}
}
impl<S, H, T> AsyncEvaluablePredicateList<S> for HCons<H, T>
where
H: AsyncEvaluablePredicate<S>,
T: AsyncEvaluablePredicateList<S>,
S: Sync + 'static,
{
fn evaluate_all_for<'s>(sub: &'s S) -> BoxFuture<'s, Result<(), BoxError>>
where
S: 's,
{
Box::pin(async move {
match H::evaluate_for(sub).await {
Ok(_) => T::evaluate_all_for(sub).await,
Err(e) => Err(e.into()),
}
})
}
}
impl<S> PredicateList<S> for HNil {
fn fmt_joined_label(buf: &mut String, sep: &str) {
if buf.ends_with(sep) {
buf.truncate(buf.len() - sep.len())
}
}
}
impl<S> PurePredicateList<S> for HNil {}
impl<S> SyncEvaluablePredicateList<S> for HNil {
#[inline]
fn evaluate_all_for(_sub: &S) -> Result<(), BoxError> {
Ok(())
}
}
impl<S> AsyncEvaluablePredicateList<S> for HNil {
#[inline]
fn evaluate_all_for<'s>(_sub: &'s S) -> BoxFuture<'s, Result<(), BoxError>>
where
S: 's,
{
Box::pin(async { Ok(()) })
}
}