Skip to main content

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}