nautilus_persistence/backend/compare.rs
1// -------------------------------------------------------------------------------------------------
2// Copyright (C) 2015-2026 Nautech Systems Pty Ltd. All rights reserved.
3// https://nautechsystems.io
4//
5// Licensed under the GNU Lesser General Public License Version 3.0 (the "License");
6// You may not use this file except in compliance with the License.
7// You may obtain a copy of the License at https://www.gnu.org/licenses/lgpl-3.0.en.html
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14// -------------------------------------------------------------------------------------------------
15
16//! Comparator trait for custom ordering.
17//!
18//! Vendored from the `compare` crate which is unmaintained.
19//! Distributed here under MIT (see `licenses/` directory).
20//! Original source: <https://github.com/contain-rs/compare>
21
22use std::cmp::Ordering::{self, Equal, Greater, Less};
23
24/// A comparator imposing a total order.
25///
26/// The `compare` method accepts two values (which may be of the same type or
27/// different types) and returns an ordering on them.
28///
29/// Comparators are useful for parameterizing the behavior of sort methods and
30/// certain data structures like binary heaps.
31pub trait Compare<L: ?Sized, R: ?Sized = L> {
32 /// Compares two values, returning `Less`, `Equal`, or `Greater` if `l` is
33 /// less than, equal to, or greater than `r`, respectively.
34 fn compare(&self, l: &L, r: &R) -> Ordering;
35
36 /// Checks if `l` is less than `r`.
37 fn compares_lt(&self, l: &L, r: &R) -> bool {
38 self.compare(l, r) == Less
39 }
40
41 /// Checks if `l` is less than or equal to `r`.
42 fn compares_le(&self, l: &L, r: &R) -> bool {
43 self.compare(l, r) != Greater
44 }
45
46 /// Checks if `l` is greater than or equal to `r`.
47 fn compares_ge(&self, l: &L, r: &R) -> bool {
48 self.compare(l, r) != Less
49 }
50
51 /// Checks if `l` is greater than `r`.
52 fn compares_gt(&self, l: &L, r: &R) -> bool {
53 self.compare(l, r) == Greater
54 }
55
56 /// Checks if `l` is equal to `r`.
57 fn compares_eq(&self, l: &L, r: &R) -> bool {
58 self.compare(l, r) == Equal
59 }
60
61 /// Checks if `l` is not equal to `r`.
62 fn compares_ne(&self, l: &L, r: &R) -> bool {
63 self.compare(l, r) != Equal
64 }
65}
66
67/// Blanket implementation for closures.
68impl<F, L: ?Sized, R: ?Sized> Compare<L, R> for F
69where
70 F: Fn(&L, &R) -> Ordering,
71{
72 fn compare(&self, l: &L, r: &R) -> Ordering {
73 (*self)(l, r)
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use std::cmp::Ordering::{Equal, Greater, Less};
80
81 use rstest::rstest;
82
83 use super::*;
84
85 struct Natural;
86
87 impl Compare<i32> for Natural {
88 fn compare(&self, l: &i32, r: &i32) -> Ordering {
89 l.cmp(r)
90 }
91 }
92
93 #[rstest]
94 fn test_compare_trait() {
95 let cmp = Natural;
96 assert_eq!(cmp.compare(&1, &2), Less);
97 assert_eq!(cmp.compare(&2, &1), Greater);
98 assert_eq!(cmp.compare(&1, &1), Equal);
99 }
100
101 #[rstest]
102 fn test_closure_comparator() {
103 let cmp = |l: &i32, r: &i32| l.cmp(r);
104 assert_eq!(cmp.compare(&1, &2), Less);
105 assert_eq!(cmp.compare(&2, &1), Greater);
106 assert_eq!(cmp.compare(&1, &1), Equal);
107 }
108
109 #[rstest]
110 fn test_reversed_ordering() {
111 let cmp = |l: &i32, r: &i32| l.cmp(r).reverse();
112 assert_eq!(cmp.compare(&1, &2), Greater);
113 assert_eq!(cmp.compare(&2, &1), Less);
114 }
115}