use std::marker::PhantomData;
use crate::entity::IEntityType;
use super::ast::BoolExpr;
#[derive(Debug, Clone)]
pub struct Predicate<T: IEntityType> {
kind: PredicateKind,
_marker: PhantomData<fn() -> T>,
}
#[derive(Debug, Clone)]
enum PredicateKind {
Always,
Never,
Expr(BoolExpr),
}
impl<T: IEntityType> Predicate<T> {
pub fn always() -> Self {
Self::with_kind(PredicateKind::Always)
}
pub fn never() -> Self {
Self::with_kind(PredicateKind::Never)
}
pub fn from_expr(expr: BoolExpr) -> Self {
Self::with_kind(PredicateKind::Expr(expr))
}
fn with_kind(kind: PredicateKind) -> Self {
Self {
kind,
_marker: PhantomData,
}
}
pub fn is_always(&self) -> bool {
matches!(self.kind, PredicateKind::Always)
}
pub fn is_never(&self) -> bool {
matches!(self.kind, PredicateKind::Never)
}
pub fn and(self, other: impl Into<Predicate<T>>) -> Self {
let rhs = other.into().kind;
let kind = match (self.kind, rhs) {
(PredicateKind::Never, _) | (_, PredicateKind::Never) => PredicateKind::Never,
(PredicateKind::Always, rhs) => rhs,
(lhs, PredicateKind::Always) => lhs,
(PredicateKind::Expr(lhs), PredicateKind::Expr(rhs)) => {
PredicateKind::Expr(BoolExpr::And(Box::new(lhs), Box::new(rhs)))
}
};
Self::with_kind(kind)
}
pub fn and_opt(self, other: Option<impl Into<Predicate<T>>>) -> Self {
match other {
Some(other) => self.and(other),
None => self,
}
}
pub fn or(self, other: impl Into<Predicate<T>>) -> Self {
let rhs = other.into().kind;
let kind = match (self.kind, rhs) {
(PredicateKind::Always, _) | (_, PredicateKind::Always) => PredicateKind::Always,
(PredicateKind::Never, rhs) => rhs,
(lhs, PredicateKind::Never) => lhs,
(PredicateKind::Expr(lhs), PredicateKind::Expr(rhs)) => {
PredicateKind::Expr(BoolExpr::Or(Box::new(lhs), Box::new(rhs)))
}
};
Self::with_kind(kind)
}
pub fn or_opt(self, other: Option<impl Into<Predicate<T>>>) -> Self {
match other {
Some(other) => self.or(other),
None => self,
}
}
#[allow(clippy::should_implement_trait)]
pub fn not(self) -> Self {
let kind = match self.kind {
PredicateKind::Always => PredicateKind::Never,
PredicateKind::Never => PredicateKind::Always,
PredicateKind::Expr(expr) => PredicateKind::Expr(BoolExpr::Not(Box::new(expr))),
};
Self::with_kind(kind)
}
pub fn into_expr(self) -> BoolExpr {
match self.kind {
PredicateKind::Always => BoolExpr::raw("1=1"),
PredicateKind::Never => BoolExpr::raw("1=0"),
PredicateKind::Expr(expr) => expr,
}
}
pub(crate) fn into_where_expr(self) -> Option<BoolExpr> {
match self.kind {
PredicateKind::Always => None,
PredicateKind::Never => Some(BoolExpr::raw("1=0")),
PredicateKind::Expr(expr) => Some(expr),
}
}
}
impl<T: IEntityType> From<BoolExpr> for Predicate<T> {
fn from(expr: BoolExpr) -> Self {
Self::from_expr(expr)
}
}
impl<T: IEntityType> From<Predicate<T>> for BoolExpr {
fn from(predicate: Predicate<T>) -> Self {
predicate.into_expr()
}
}