use super::SortDirection;
use std::cmp::Ordering;
use std::fmt;
use std::rc::Rc;
pub struct SortExpression<T> {
direction: SortDirection,
expression: Rc<dyn Fn(&T, &T) -> Ordering>,
}
impl<T> Clone for SortExpression<T> {
fn clone(&self) -> Self {
Self { direction: self.direction, expression: self.expression.clone() }
}
}
impl<T> fmt::Debug for SortExpression<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SortExpression").field("direction", &self.direction).finish_non_exhaustive()
}
}
impl<T: 'static> SortExpression<T> {
pub fn new<V: PartialOrd + 'static>(expression: impl Fn(&T) -> V + 'static, direction: SortDirection) -> Self {
Self { direction, expression: Rc::new(move |x: &T, y: &T| expression(x).partial_cmp(&expression(y)).unwrap_or(Ordering::Equal)) }
}
pub fn ascending<V: PartialOrd + 'static>(expression: impl Fn(&T) -> V + 'static) -> Self {
Self::new(expression, SortDirection::Ascending)
}
}
impl<T> SortExpression<T> {
pub fn direction(&self) -> SortDirection {
self.direction
}
pub fn compare_values(&self, x: &T, y: &T) -> Ordering {
(self.expression)(x, y)
}
}
pub struct SortExpressionComparer<T> {
expressions: Vec<SortExpression<T>>,
}
impl<T> Clone for SortExpressionComparer<T> {
fn clone(&self) -> Self {
Self { expressions: self.expressions.clone() }
}
}
impl<T> Default for SortExpressionComparer<T> {
fn default() -> Self {
Self { expressions: Vec::new() }
}
}
impl<T> fmt::Debug for SortExpressionComparer<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_list().entries(self.expressions.iter()).finish()
}
}
impl<T: 'static> SortExpressionComparer<T> {
pub fn ascending<V: PartialOrd + 'static>(expression: impl Fn(&T) -> V + 'static) -> Self {
Self { expressions: vec![SortExpression::new(expression, SortDirection::Ascending)] }
}
pub fn descending<V: PartialOrd + 'static>(expression: impl Fn(&T) -> V + 'static) -> Self {
Self { expressions: vec![SortExpression::new(expression, SortDirection::Descending)] }
}
pub fn then_by_ascending<V: PartialOrd + 'static>(mut self, expression: impl Fn(&T) -> V + 'static) -> Self {
self.expressions.push(SortExpression::new(expression, SortDirection::Ascending));
self
}
pub fn then_by_descending<V: PartialOrd + 'static>(mut self, expression: impl Fn(&T) -> V + 'static) -> Self {
self.expressions.push(SortExpression::new(expression, SortDirection::Descending));
self
}
pub fn comparer(&self) -> Rc<dyn Fn(&T, &T) -> Ordering> {
let comparer = self.clone();
Rc::new(move |x: &T, y: &T| comparer.compare(x, y))
}
}
impl<T> SortExpressionComparer<T> {
pub fn push(&mut self, expression: SortExpression<T>) {
self.expressions.push(expression);
}
pub fn expressions(&self) -> &[SortExpression<T>] {
&self.expressions
}
pub fn compare(&self, x: &T, y: &T) -> Ordering {
for item in &self.expressions {
let result = item.compare_values(x, y);
if result == Ordering::Equal {
continue;
}
return match item.direction() {
SortDirection::Ascending => result,
SortDirection::Descending => result.reverse(),
};
}
Ordering::Equal
}
}
impl<T: 'static> From<SortExpressionComparer<T>> for Rc<dyn Fn(&T, &T) -> Ordering> {
fn from(comparer: SortExpressionComparer<T>) -> Self {
Rc::new(move |x: &T, y: &T| comparer.compare(x, y))
}
}