#![allow(private_bounds, private_interfaces)]
use crate::{
Bool, Comparable, Likeable, LowerCompatible, Orderable, TypeMeta, count_idents,
expression::{Expression, Operator},
impl_for_all_tuples,
lower::{Instructions, LowerCtx},
};
pub struct Any<T> {
inner: T,
}
pub struct All<T> {
inner: T,
}
pub struct None<T> {
inner: T,
}
pub struct GroupPredicate<G, R, Op> {
group: G,
right: R,
op: Op,
}
#[doc(hidden)]
pub struct EqOp;
#[doc(hidden)]
pub struct NeqOp;
#[doc(hidden)]
pub struct LtOp;
#[doc(hidden)]
pub struct LteOp;
#[doc(hidden)]
pub struct GtOp;
#[doc(hidden)]
pub struct GteOp;
#[doc(hidden)]
pub struct LikeOp {
case_sensitive: bool,
negated: bool,
}
pub fn any<T>(inner: T) -> Any<T> {
Any { inner }
}
pub fn all<T>(inner: T) -> All<T> {
All { inner }
}
pub fn none<T>(inner: T) -> None<T> {
None { inner }
}
macro_rules! impl_group_methods {
(
$group:ident,
$negated_eq:ident,
$negated_neq:ident,
$negated_lt:ident,
$negated_lte:ident,
$negated_gt:ident,
$negated_gte:ident,
$like_negated:expr
) => {
impl<T> $group<T> {
pub fn eq<R>(self, right: R) -> GroupPredicate<Self, R, $negated_eq>
where
T: LowerTuplePredicate<R, $negated_eq>,
T::Type: Comparable,
R: LowerCompatible<T::Type>,
{
GroupPredicate {
group: self,
right,
op: $negated_eq,
}
}
pub fn neq<R>(self, right: R) -> GroupPredicate<Self, R, $negated_neq>
where
T: LowerTuplePredicate<R, $negated_neq>,
T::Type: Comparable,
R: LowerCompatible<T::Type>,
{
GroupPredicate {
group: self,
right,
op: $negated_neq,
}
}
pub fn lt<R>(self, right: R) -> GroupPredicate<Self, R, $negated_lt>
where
T: LowerTuplePredicate<R, $negated_lt>,
T::Type: Orderable,
R: LowerCompatible<T::Type>,
{
GroupPredicate {
group: self,
right,
op: $negated_lt,
}
}
pub fn lte<R>(self, right: R) -> GroupPredicate<Self, R, $negated_lte>
where
T: LowerTuplePredicate<R, $negated_lte>,
T::Type: Orderable,
R: LowerCompatible<T::Type>,
{
GroupPredicate {
group: self,
right,
op: $negated_lte,
}
}
pub fn gt<R>(self, right: R) -> GroupPredicate<Self, R, $negated_gt>
where
T: LowerTuplePredicate<R, $negated_gt>,
T::Type: Orderable,
R: LowerCompatible<T::Type>,
{
GroupPredicate {
group: self,
right,
op: $negated_gt,
}
}
pub fn gte<R>(self, right: R) -> GroupPredicate<Self, R, $negated_gte>
where
T: LowerTuplePredicate<R, $negated_gte>,
T::Type: Orderable,
R: LowerCompatible<T::Type>,
{
GroupPredicate {
group: self,
right,
op: $negated_gte,
}
}
pub fn like<R>(self, right: R) -> GroupPredicate<Self, R, LikeOp>
where
T: LowerTuplePredicate<R, LikeOp>,
T::Type: Likeable,
R: LowerCompatible<T::Type>,
{
GroupPredicate {
group: self,
right,
op: LikeOp {
case_sensitive: false,
negated: $like_negated,
},
}
}
}
};
}
impl_group_methods!(Any, EqOp, NeqOp, LtOp, LteOp, GtOp, GteOp, false);
impl_group_methods!(All, EqOp, NeqOp, LtOp, LteOp, GtOp, GteOp, false);
impl_group_methods!(None, NeqOp, EqOp, GteOp, GtOp, LteOp, LtOp, true);
impl<G, R> GroupPredicate<G, R, LikeOp> {
pub fn case_sensitive(mut self) -> Self {
self.op.case_sensitive = true;
self
}
}
trait GroupedPredicateOp<T, R> {
fn lower<L>(&self, left: &L, ctx: &mut LowerCtx, right: &R) -> usize
where
L: Expression<Type = T>;
}
impl<T, R> GroupedPredicateOp<T, R> for EqOp
where
T: Comparable,
R: LowerCompatible<T>,
{
fn lower<L>(&self, left: &L, ctx: &mut LowerCtx, right: &R) -> usize
where
L: Expression<Type = T>,
{
let lhs = left.lower(ctx);
let rhs = right.lower_compatible(ctx);
ctx.instrs.push_binary(Operator::Eq, lhs, rhs);
lhs + rhs + 1
}
}
impl<T, R> GroupedPredicateOp<T, R> for NeqOp
where
T: Comparable,
R: LowerCompatible<T>,
{
fn lower<L>(&self, left: &L, ctx: &mut LowerCtx, right: &R) -> usize
where
L: Expression<Type = T>,
{
let lhs = left.lower(ctx);
let rhs = right.lower_compatible(ctx);
ctx.instrs.push_binary(Operator::Neq, lhs, rhs);
lhs + rhs + 1
}
}
macro_rules! impl_grouped_order_op {
($name:ty, $operator:expr) => {
impl<T, R> GroupedPredicateOp<T, R> for $name
where
T: Orderable,
R: LowerCompatible<T>,
{
fn lower<L>(&self, left: &L, ctx: &mut LowerCtx, right: &R) -> usize
where
L: Expression<Type = T>,
{
let lhs = left.lower(ctx);
let rhs = right.lower_compatible(ctx);
ctx.instrs.push_binary($operator, lhs, rhs);
lhs + rhs + 1
}
}
};
}
impl_grouped_order_op!(LtOp, Operator::Lt);
impl_grouped_order_op!(LteOp, Operator::Lte);
impl_grouped_order_op!(GtOp, Operator::Gt);
impl_grouped_order_op!(GteOp, Operator::Gte);
impl<T, R> GroupedPredicateOp<T, R> for LikeOp
where
T: Likeable,
R: LowerCompatible<T>,
{
fn lower<L>(&self, left: &L, ctx: &mut LowerCtx, right: &R) -> usize
where
L: Expression<Type = T>,
{
let lhs = left.lower(ctx);
let rhs = right.lower_compatible(ctx);
ctx.instrs.push_binary(
Operator::Like {
sensitive: self.case_sensitive,
negated: self.negated,
},
lhs,
rhs,
);
lhs + rhs + 1
}
}
#[doc(hidden)]
pub trait LowerTuplePredicate<R, Op> {
type Type: TypeMeta;
fn lower_tuple_predicate(
&self,
ctx: &mut LowerCtx,
right: &R,
op: &Op,
combine: Operator,
) -> usize
where
Op: GroupedPredicateOp<Self::Type, R>;
}
impl<A, R, Op> LowerTuplePredicate<R, Op> for (A,)
where
A: Expression,
Op: GroupedPredicateOp<A::Type, R>,
{
type Type = A::Type;
fn lower_tuple_predicate(
&self,
ctx: &mut LowerCtx,
right: &R,
op: &Op,
_combine: Operator,
) -> usize
where
Op: GroupedPredicateOp<Self::Type, R>,
{
let (a,) = self;
op.lower(a, ctx, right)
}
}
macro_rules! impl_tuple_predicate {
($($T:ident),+) => {
impl<Type, R, Op, $($T,)+> LowerTuplePredicate<R, Op> for ($($T,)+)
where
Type: TypeMeta,
Op: GroupedPredicateOp<Type, R>,
$($T: Expression<Type = Type>,)+
{
type Type = Type;
fn lower_tuple_predicate(
&self,
ctx: &mut LowerCtx,
right: &R,
op: &Op,
combine: Operator,
) -> usize
where
Op: GroupedPredicateOp<Self::Type, R>,
{
#[allow(non_snake_case)]
let ($($T,)+) = self;
let mut total = None::<usize>;
$(
let piece = op.lower($T, ctx, right);
if let Some(existing) = total {
ctx.instrs.push_binary(combine, existing, piece);
total = Some(existing + piece + 1);
} else {
total = Some(piece);
}
)+
let _ = count_idents!($($T,)+);
total.expect("tuple expressions must contain at least one field")
}
}
};
}
impl_for_all_tuples!(impl_tuple_predicate);
trait LowerGroupPredicate<R, Op> {
type Type: TypeMeta;
fn lower_group_predicate(&self, ctx: &mut LowerCtx, right: &R, op: &Op) -> usize
where
R: LowerCompatible<Self::Type>,
Op: GroupedPredicateOp<Self::Type, R>;
}
impl<T, R, Op> LowerGroupPredicate<R, Op> for Any<T>
where
T: LowerTuplePredicate<R, Op>,
{
type Type = T::Type;
fn lower_group_predicate(&self, ctx: &mut LowerCtx, right: &R, op: &Op) -> usize
where
R: LowerCompatible<Self::Type>,
Op: GroupedPredicateOp<Self::Type, R>,
{
self.inner
.lower_tuple_predicate(ctx, right, op, Operator::Or)
}
}
impl<T, R, Op> LowerGroupPredicate<R, Op> for All<T>
where
T: LowerTuplePredicate<R, Op>,
{
type Type = T::Type;
fn lower_group_predicate(&self, ctx: &mut LowerCtx, right: &R, op: &Op) -> usize
where
R: LowerCompatible<Self::Type>,
Op: GroupedPredicateOp<Self::Type, R>,
{
self.inner
.lower_tuple_predicate(ctx, right, op, Operator::And)
}
}
impl<T, R, Op> LowerGroupPredicate<R, Op> for None<T>
where
T: LowerTuplePredicate<R, Op>,
{
type Type = T::Type;
fn lower_group_predicate(&self, ctx: &mut LowerCtx, right: &R, op: &Op) -> usize
where
R: LowerCompatible<Self::Type>,
Op: GroupedPredicateOp<Self::Type, R>,
{
self.inner
.lower_tuple_predicate(ctx, right, op, Operator::And)
}
}
#[qraft_expression_macro::as_expression]
impl<G, R, Op> Expression for GroupPredicate<G, R, Op>
where
G: LowerGroupPredicate<R, Op>,
R: LowerCompatible<G::Type>,
Op: GroupedPredicateOp<G::Type, R>,
{
type Type = Bool;
fn lower(&self, ctx: &mut LowerCtx) -> usize {
self.group.lower_group_predicate(ctx, &self.right, &self.op)
}
}