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))
}
}