use crate::{
LowerCompatible, NullOf, PredicateType, TypeMeta, UnaryType, count_idents,
expression::Expression,
impl_for_all_tuples,
lower::{Instructions, LowerCtx},
ty::Nullability,
};
pub struct InList<L, R> {
lhs: L,
rhs: R,
negated: bool,
}
#[qraft_expression_macro::as_expression]
impl<L, R> Expression for InList<L, R>
where
L: Expression,
L::Type: Nullability,
R: LowerIn<L::Type>,
UnaryType<NullOf<L::Type>>: PredicateType,
{
type Type = <UnaryType<NullOf<L::Type>> as PredicateType>::Output;
fn lower(&self, ctx: &mut LowerCtx) -> usize {
let lhs = self.lhs.lower(ctx);
let rhs = self.rhs.lower_in(ctx);
ctx.lower_in(self.negated, lhs, rhs)
}
}
pub trait In: Sized + Expression {
fn one_of<R>(self, list: R) -> InList<Self, R>
where
R: LowerIn<Self::Type>,
{
self.in_(list)
}
fn in_<R>(self, list: R) -> InList<Self, R>
where
R: LowerIn<Self::Type>,
{
InList {
lhs: self,
rhs: list,
negated: false,
}
}
fn not_in<R>(self, list: R) -> InList<Self, R>
where
R: LowerIn<Self::Type>,
{
InList {
lhs: self,
rhs: list,
negated: true,
}
}
}
impl<E> In for E where E: Expression {}
pub trait LowerIn<T> {
fn lower_in(&self, ctx: &mut LowerCtx) -> usize;
}
impl<Type, A> LowerIn<Type> for (A,)
where
Type: TypeMeta,
A: LowerCompatible<Type>,
{
fn lower_in(&self, ctx: &mut LowerCtx) -> usize {
let (a,) = self;
let inner = a.lower_compatible(ctx);
ctx.instrs.push_seperated(1);
inner + 1
}
}
impl<Type, A> LowerIn<Type> for Vec<A>
where
Type: TypeMeta,
A: LowerCompatible<Type>,
{
fn lower_in(&self, ctx: &mut LowerCtx) -> usize {
let len = self.len();
let mut inner = 0;
for item in self {
inner += item.lower_compatible(ctx);
}
ctx.instrs.push_seperated(len);
inner + 1
}
}
impl<Type, A, const N: usize> LowerIn<Type> for [A; N]
where
Type: TypeMeta,
A: LowerCompatible<Type>,
{
fn lower_in(&self, ctx: &mut LowerCtx) -> usize {
let len = self.len();
let mut inner = 0;
for item in self {
inner += item.lower_compatible(ctx);
}
ctx.instrs.push_seperated(len);
inner + 1
}
}
macro_rules! impl_in_macro {
($($T:ident),+) => {
impl<Type, $($T,)+> LowerIn<Type> for ($($T,)+)
where
Type: TypeMeta,
$($T: LowerCompatible<Type>,)+
{
fn lower_in(&self, ctx: &mut LowerCtx) -> usize {
let mut inner = 0;
#[allow(non_snake_case)]
let ($($T,)+) = self;
$(
inner += $T.lower_compatible(ctx);
)+
let count = count_idents!($($T,)+);
ctx.instrs.push_seperated(count);
inner + 1
}
}
};
}
impl_for_all_tuples!(impl_in_macro);