mem-query 0.0.1

Relational algebra interface for Rust collections
use {
    crate::{
        col::Col,
        rename_col::RenameCol,
        header::{Header, HasCol, ProjectFrom},
        record::Record,
    },
    tylisp::{
        sexpr,
        non_calc_literal,
        engine::Eval,
        ops::{
            list::Concat,
        }
    },
    std::{
        marker::PhantomData,
        cmp::{Ord, Ordering},
    },
    either::Either,
};

pub trait SortKey {
    type ReqCols: Header;

    fn cmp_raw<R:Record<Cols=Self::ReqCols>>(a:&R, b:&R)->Ordering;

    #[inline(always)]
    fn cmp<R: Record>(a:&R, b:&R)->Ordering
    where Self::ReqCols: ProjectFrom<R::Cols> {
        Self::cmp_raw(&a.project(), &b.project())
    }

    #[inline(always)]
    fn sort<R: Record, I:Iterator<Item = R>>(results: I)
    ->Either<std::vec::IntoIter<R>, I> 
    where Self::ReqCols: ProjectFrom<R::Cols> {
        let mut results: Vec<R> = results.collect();
        results.sort_by(Self::cmp::<R>);
        Either::Left(results.into_iter())
    }
}

pub trait Presorted<K> {
    type SubSort: SortKey;
    type PostSort: SortKey;
}

#[derive(Copy, Clone, Debug)]
pub struct Asc<C:Col>(PhantomData<fn(C)>);
non_calc_literal!({C:Col} Asc<C>);

#[derive(Copy, Clone, Debug)]
pub struct Desc<C:Col>(PhantomData<fn(C)>);
non_calc_literal!({C:Col} Desc<C>);

impl<A,B,T> RenameCol<A,B> for Asc<T>
where A: Col, B:Col<Inner = A::Inner>,
    T: Col + RenameCol<A,B>,
    T::Renamed: Col,
    Asc<T::Renamed>: SortKey {
    type Renamed = Asc<T::Renamed>;
    fn rename_col(self)->Self::Renamed { unreachable!() }
}

impl<A,B,T> RenameCol<A,B> for Desc<T>
where A: Col, B:Col<Inner = A::Inner>,
    T: Col + RenameCol<A,B>,
    T::Renamed: Col,
    Desc<T::Renamed>: SortKey {
    type Renamed = Desc<T::Renamed>;
    fn rename_col(self)->Self::Renamed { unreachable!() }
}

impl<C:Col+Ord> SortKey for Asc<C>
where sexpr!{C}: Header + HasCol<C> {
    type ReqCols = sexpr!{C};

    #[inline(always)]
    fn cmp_raw<R:Record<Cols=Self::ReqCols>>(a:&R, b:&R)->Ordering {
        a.col_ref().cmp(b.col_ref())
    }
}

impl<C:Col+Ord> SortKey for Desc<C>
where sexpr!{C}: Header + HasCol<C> {
    type ReqCols = sexpr!{C};

    #[inline(always)]
    fn cmp_raw<R:Record<Cols=Self::ReqCols>>(a:&R, b:&R)->Ordering {
        a.col_ref().cmp(b.col_ref()).reverse()
    }
}

impl SortKey for sexpr!{} {
    type ReqCols = sexpr!{};

    #[inline(always)]
    fn cmp_raw<R:Record<Cols=Self::ReqCols>>(_:&R, _:&R)->Ordering {
        Ordering::Equal
    }

    #[inline(always)]
    fn sort<R: Record, I:Iterator<Item = R>>(results: I)
    ->Either<std::vec::IntoIter<R>, I> {
        Either::Right(results)
    }
}

impl<H,T,ReqCols> SortKey for sexpr!{H;T}
where H: SortKey, T:SortKey,
      sexpr!{Concat, @H::ReqCols, @T::ReqCols}: Eval<Result=ReqCols>,
      ReqCols: Header,
      H::ReqCols: ProjectFrom<ReqCols>,
      T::ReqCols: ProjectFrom<ReqCols>,
{
    type ReqCols = ReqCols;

    #[inline(always)]
    fn cmp_raw<R:Record<Cols=Self::ReqCols>>(a:&R, b:&R)->Ordering {
        H::cmp(a, b).then_with(|| T::cmp(a, b))
    }
}