const_str/__ctfe/
compare.rs

1use core::cmp::Ordering;
2
3pub struct Compare<T1, T2>(pub T1, pub T2);
4
5impl Compare<&[u8], &[u8]> {
6    pub const fn const_eval(&self) -> Ordering {
7        crate::bytes::compare(self.0, self.1)
8    }
9}
10
11impl<const L1: usize, const L2: usize> Compare<&[u8; L1], &[u8; L2]> {
12    pub const fn const_eval(&self) -> Ordering {
13        crate::bytes::compare(self.0, self.1)
14    }
15}
16
17impl Compare<&str, &str> {
18    pub const fn const_eval(&self) -> Ordering {
19        crate::str::compare(self.0, self.1)
20    }
21}
22
23/// Compares two strings lexicographically.
24///
25/// This macro is [const-fn compatible](./index.html#const-fn-compatible).
26///
27/// See also [`equal!`](crate::equal).
28///
29/// # Examples
30///
31/// ```
32/// use core::cmp::Ordering;
33///
34/// const A: &str = "1";
35/// const B: &str = "10";
36/// const C: &str = "2";
37///
38/// const ORD: Ordering = const_str::compare!(A, B);
39/// assert_eq!(ORD, Ordering::Less);
40///
41/// assert!(const_str::compare!(<, A, B));
42/// assert!(const_str::compare!(<=, A, B));
43///
44/// assert!(const_str::compare!(>, C, A));
45/// assert!(const_str::compare!(>=, C, A));
46///
47/// assert!(const_str::compare!(==, A, A));
48/// ```
49///
50#[macro_export]
51macro_rules! compare {
52    (<, $lhs: expr, $rhs: expr) => {{
53        use ::core::cmp::Ordering;
54        let ordering = $crate::__ctfe::Compare($lhs, $rhs).const_eval();
55        matches!(ordering, Ordering::Less)
56    }};
57    (>, $lhs: expr, $rhs: expr) => {{
58        use ::core::cmp::Ordering;
59        let ordering = $crate::__ctfe::Compare($lhs, $rhs).const_eval();
60        matches!(ordering, Ordering::Greater)
61    }};
62    (==, $lhs: expr, $rhs: expr) => {{
63        use ::core::cmp::Ordering;
64        let ordering = $crate::__ctfe::Compare($lhs, $rhs).const_eval();
65        matches!(ordering, Ordering::Equal)
66    }};
67    (<=, $lhs: expr, $rhs: expr) => {{
68        use ::core::cmp::Ordering;
69        let ordering = $crate::__ctfe::Compare($lhs, $rhs).const_eval();
70        matches!(ordering, Ordering::Less | Ordering::Equal)
71    }};
72    (>=, $lhs: expr, $rhs: expr) => {{
73        use ::core::cmp::Ordering;
74        let ordering = $crate::__ctfe::Compare($lhs, $rhs).const_eval();
75        matches!(ordering, Ordering::Greater | Ordering::Equal)
76    }};
77    ($lhs: expr, $rhs: expr) => {
78        $crate::__ctfe::Compare($lhs, $rhs).const_eval()
79    };
80}
81
82#[cfg(test)]
83mod tests {
84    use core::cmp::Ordering;
85
86    #[test]
87    fn test_compare_str() {
88        const A: &str = "apple";
89        const B: &str = "banana";
90        const C: &str = "apple";
91
92        const ORD1: Ordering = compare!(A, B);
93        const ORD2: Ordering = compare!(B, A);
94        const ORD3: Ordering = compare!(A, C);
95
96        assert_eq!(ORD1, Ordering::Less);
97        assert_eq!(ORD2, Ordering::Greater);
98        assert_eq!(ORD3, Ordering::Equal);
99
100        let lt = compare!(<, A, B);
101        let gt = compare!(>, B, A);
102        let eq = compare!(==, A, C);
103        let le1 = compare!(<=, A, B);
104        let le2 = compare!(<=, A, C);
105        let ge1 = compare!(>=, B, A);
106        let ge2 = compare!(>=, A, C);
107
108        assert!(lt);
109        assert!(gt);
110        assert!(eq);
111        assert!(le1);
112        assert!(le2);
113        assert!(ge1);
114        assert!(ge2);
115    }
116
117    #[test]
118    fn test_compare_bytes() {
119        const A: &[u8] = b"apple";
120        const B: &[u8] = b"banana";
121        const C: &[u8] = b"apple";
122
123        const ORD1: Ordering = compare!(A, B);
124        const ORD2: Ordering = compare!(B, A);
125        const ORD3: Ordering = compare!(A, C);
126
127        assert_eq!(ORD1, Ordering::Less);
128        assert_eq!(ORD2, Ordering::Greater);
129        assert_eq!(ORD3, Ordering::Equal);
130    }
131
132    #[test]
133    fn test_compare_byte_arrays() {
134        const A: &[u8; 5] = b"apple";
135        const B: &[u8; 6] = b"banana";
136        const C: &[u8; 5] = b"apple";
137
138        const ORD1: Ordering = compare!(A, B);
139        const ORD2: Ordering = compare!(B, A);
140        const ORD3: Ordering = compare!(A, C);
141
142        assert_eq!(ORD1, Ordering::Less);
143        assert_eq!(ORD2, Ordering::Greater);
144        assert_eq!(ORD3, Ordering::Equal);
145    }
146
147    #[test]
148    fn test_compare_runtime() {
149        use super::*;
150
151        // Runtime tests for Compare with &str
152        let cmp_str = Compare("apple", "banana");
153        assert_eq!(cmp_str.const_eval(), Ordering::Less);
154
155        let cmp_str2 = Compare("zebra", "apple");
156        assert_eq!(cmp_str2.const_eval(), Ordering::Greater);
157
158        let cmp_str3 = Compare("test", "test");
159        assert_eq!(cmp_str3.const_eval(), Ordering::Equal);
160
161        // Runtime tests for Compare with bytes
162        let cmp_bytes = Compare(b"hello".as_slice(), b"world".as_slice());
163        assert_eq!(cmp_bytes.const_eval(), Ordering::Less);
164
165        // Runtime tests for Compare with byte arrays
166        let arr1: &[u8; 3] = b"abc";
167        let arr2: &[u8; 3] = b"xyz";
168        let cmp_arr = Compare(arr1, arr2);
169        assert_eq!(cmp_arr.const_eval(), Ordering::Less);
170    }
171}