pub trait Specification<T>: Send + Sync {
fn is_satisfied_by(&self, t: &T) -> bool;
fn and<S>(self, other: S) -> AndSpec<Self, S>
where
Self: Sized,
S: Specification<T>,
{
AndSpec { a: self, b: other }
}
fn or<S>(self, other: S) -> OrSpec<Self, S>
where
Self: Sized,
S: Specification<T>,
{
OrSpec { a: self, b: other }
}
fn not(self) -> NotSpec<Self>
where
Self: Sized,
{
NotSpec { inner: self }
}
}
pub struct AndSpec<A, B> {
a: A,
b: B,
}
impl<T, A: Specification<T>, B: Specification<T>> Specification<T> for AndSpec<A, B> {
fn is_satisfied_by(&self, t: &T) -> bool {
self.a.is_satisfied_by(t) && self.b.is_satisfied_by(t)
}
}
pub struct OrSpec<A, B> {
a: A,
b: B,
}
impl<T, A: Specification<T>, B: Specification<T>> Specification<T> for OrSpec<A, B> {
fn is_satisfied_by(&self, t: &T) -> bool {
self.a.is_satisfied_by(t) || self.b.is_satisfied_by(t)
}
}
pub struct NotSpec<S> {
inner: S,
}
impl<T, S: Specification<T>> Specification<T> for NotSpec<S> {
fn is_satisfied_by(&self, t: &T) -> bool {
!self.inner.is_satisfied_by(t)
}
}
pub struct FnSpec<F>(pub F);
impl<T, F: Fn(&T) -> bool + Send + Sync> Specification<T> for FnSpec<F> {
fn is_satisfied_by(&self, t: &T) -> bool {
(self.0)(t)
}
}