ferroui_dynamic_data/binding/
sort_expression_comparer.rs1use super::SortDirection;
5use std::cmp::Ordering;
6use std::fmt;
7use std::rc::Rc;
8
9pub struct SortExpression<T> {
16 direction: SortDirection,
17 expression: Rc<dyn Fn(&T, &T) -> Ordering>,
18}
19
20impl<T> Clone for SortExpression<T> {
21 fn clone(&self) -> Self {
22 Self { direction: self.direction, expression: self.expression.clone() }
23 }
24}
25
26impl<T> fmt::Debug for SortExpression<T> {
27 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
28 f.debug_struct("SortExpression").field("direction", &self.direction).finish_non_exhaustive()
29 }
30}
31
32impl<T: 'static> SortExpression<T> {
33 pub fn new<V: PartialOrd + 'static>(expression: impl Fn(&T) -> V + 'static, direction: SortDirection) -> Self {
35 Self { direction, expression: Rc::new(move |x: &T, y: &T| expression(x).partial_cmp(&expression(y)).unwrap_or(Ordering::Equal)) }
36 }
37
38 pub fn ascending<V: PartialOrd + 'static>(expression: impl Fn(&T) -> V + 'static) -> Self {
40 Self::new(expression, SortDirection::Ascending)
41 }
42}
43
44impl<T> SortExpression<T> {
45 pub fn direction(&self) -> SortDirection {
47 self.direction
48 }
49
50 pub fn compare_values(&self, x: &T, y: &T) -> Ordering {
53 (self.expression)(x, y)
54 }
55}
56
57pub struct SortExpressionComparer<T> {
64 expressions: Vec<SortExpression<T>>,
65}
66
67impl<T> Clone for SortExpressionComparer<T> {
68 fn clone(&self) -> Self {
69 Self { expressions: self.expressions.clone() }
70 }
71}
72
73impl<T> Default for SortExpressionComparer<T> {
74 fn default() -> Self {
76 Self { expressions: Vec::new() }
77 }
78}
79
80impl<T> fmt::Debug for SortExpressionComparer<T> {
81 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
82 f.debug_list().entries(self.expressions.iter()).finish()
83 }
84}
85
86impl<T: 'static> SortExpressionComparer<T> {
87 pub fn ascending<V: PartialOrd + 'static>(expression: impl Fn(&T) -> V + 'static) -> Self {
89 Self { expressions: vec![SortExpression::new(expression, SortDirection::Ascending)] }
90 }
91
92 pub fn descending<V: PartialOrd + 'static>(expression: impl Fn(&T) -> V + 'static) -> Self {
94 Self { expressions: vec![SortExpression::new(expression, SortDirection::Descending)] }
95 }
96
97 pub fn then_by_ascending<V: PartialOrd + 'static>(mut self, expression: impl Fn(&T) -> V + 'static) -> Self {
99 self.expressions.push(SortExpression::new(expression, SortDirection::Ascending));
100 self
101 }
102
103 pub fn then_by_descending<V: PartialOrd + 'static>(mut self, expression: impl Fn(&T) -> V + 'static) -> Self {
105 self.expressions.push(SortExpression::new(expression, SortDirection::Descending));
106 self
107 }
108
109 pub fn comparer(&self) -> Rc<dyn Fn(&T, &T) -> Ordering> {
111 let comparer = self.clone();
112 Rc::new(move |x: &T, y: &T| comparer.compare(x, y))
113 }
114}
115
116impl<T> SortExpressionComparer<T> {
117 pub fn push(&mut self, expression: SortExpression<T>) {
119 self.expressions.push(expression);
120 }
121
122 pub fn expressions(&self) -> &[SortExpression<T>] {
124 &self.expressions
125 }
126
127 pub fn compare(&self, x: &T, y: &T) -> Ordering {
129 for item in &self.expressions {
130 let result = item.compare_values(x, y);
131 if result == Ordering::Equal {
132 continue;
133 }
134 return match item.direction() {
135 SortDirection::Ascending => result,
136 SortDirection::Descending => result.reverse(),
137 };
138 }
139 Ordering::Equal
140 }
141}
142
143impl<T: 'static> From<SortExpressionComparer<T>> for Rc<dyn Fn(&T, &T) -> Ordering> {
144 fn from(comparer: SortExpressionComparer<T>) -> Self {
145 Rc::new(move |x: &T, y: &T| comparer.compare(x, y))
146 }
147}