use async_trait::async_trait;
use super::{Predicate, PredicateResult};
#[derive(Debug)]
pub struct Not<P> {
predicate: P,
}
impl<P> Not<P> {
pub fn new(predicate: P) -> Self {
Self { predicate }
}
}
#[async_trait]
impl<P> Predicate for Not<P>
where
P: Predicate + Send + Sync,
P::Subject: Send,
{
type Subject = P::Subject;
async fn check(&self, subject: Self::Subject) -> PredicateResult<Self::Subject> {
match self.predicate.check(subject).await {
PredicateResult::Cacheable(s) => PredicateResult::NonCacheable(s),
PredicateResult::NonCacheable(s) => PredicateResult::Cacheable(s),
}
}
}
#[derive(Debug)]
pub struct And<L, R> {
left: L,
right: R,
}
impl<L, R> And<L, R> {
pub fn new(left: L, right: R) -> Self {
Self { left, right }
}
}
#[async_trait]
impl<L, R> Predicate for And<L, R>
where
L: Predicate + Send + Sync,
R: Predicate<Subject = L::Subject> + Send + Sync,
L::Subject: Send,
{
type Subject = L::Subject;
async fn check(&self, subject: Self::Subject) -> PredicateResult<Self::Subject> {
match self.left.check(subject).await {
PredicateResult::Cacheable(s) => self.right.check(s).await,
non_cacheable => non_cacheable,
}
}
}
#[derive(Debug)]
pub struct Or<L, R> {
left: L,
right: R,
}
impl<L, R> Or<L, R> {
pub fn new(left: L, right: R) -> Self {
Self { left, right }
}
}
#[async_trait]
impl<L, R> Predicate for Or<L, R>
where
L: Predicate + Send + Sync,
R: Predicate<Subject = L::Subject> + Send + Sync,
L::Subject: Send,
{
type Subject = L::Subject;
async fn check(&self, subject: Self::Subject) -> PredicateResult<Self::Subject> {
match self.left.check(subject).await {
PredicateResult::NonCacheable(s) => self.right.check(s).await,
cacheable => cacheable,
}
}
}
pub trait PredicateExt: Predicate + Sized {
fn and<R>(self, right: R) -> And<Self, R>
where
R: Predicate<Subject = Self::Subject>,
{
And::new(self, right)
}
fn or<R>(self, right: R) -> Or<Self, R>
where
R: Predicate<Subject = Self::Subject>,
{
Or::new(self, right)
}
fn not(self) -> Not<Self> {
Not::new(self)
}
fn boxed(self) -> Box<dyn Predicate<Subject = Self::Subject> + Send + Sync>
where
Self: Send + Sync + 'static,
{
Box::new(self)
}
}
impl<T: Predicate + Sized> PredicateExt for T {}