stringlet/
cmp.rs

1//! `Eq` & `Ord` implementations
2
3use crate::*;
4
5use core::cmp::Ordering;
6
7// Needed where explicitly requested, e.g. HashMap key
8impl_for! { Eq }
9
10impl_for! {
11    <2> PartialEq<StringletBase<SIZE2, FIXED2, LEN2, ALIGN2>>:
12
13    #[inline]
14    fn eq(&self, other: &StringletBase<SIZE2, FIXED2, LEN2, ALIGN2>) -> bool {
15        match (SIZE == SIZE2, FIXED, FIXED2) {
16            // Slice only needed because the compiler can’t reason about these types being same.
17            // Would need specialization, with either both being SIZE or SIZE != SIZE2.
18            (true, ..) => SIZE == 0 || self.str == other.str[..],
19
20            // Fixeds can only be same at same length.
21            (_, true, true) => false,
22
23            // Either fixed one can only be eq if shorter; and it doesn’t need a dynamic slice
24            (_, true, _) => SIZE < SIZE2 && self.str == other.str[..other.len()],
25            (.., true) => SIZE > SIZE2 && self.str[..self.len()] == other.str,
26            _ => self.str[..self.len()] == other.str[..other.len()],
27        }
28    }
29}
30
31impl_for! {
32    <'a, 2> PartialEq<&'a StringletBase<SIZE2, FIXED2, LEN2, ALIGN2>>:
33
34    #[inline(always)]
35    fn eq(&self, other: &&'a StringletBase<SIZE2, FIXED2, LEN2, ALIGN2>) -> bool {
36        self.eq(*other)
37    }
38}
39
40impl_for! {
41    PartialEq<str>:
42
43    #[inline]
44    fn eq(&self, other: &str) -> bool {
45        if SIZE == 0 {
46            other.is_empty()
47        } else if FIXED {
48            self.str == *other.as_bytes()
49        } else {
50            self.str[..self.len()] == *other.as_bytes()
51        }
52    }
53}
54
55impl_for! {
56    <'a> PartialEq<&'a str>:
57
58    #[inline(always)]
59    fn eq(&self, other: &&'a str) -> bool {
60        self.eq(*other)
61    }
62}
63
64// Gnats: Ord falls short of PartialEq, in that I can only compare to Self
65/* impl_for! {
66    Ord:
67
68    fn cmp(&self, other: &Self) -> Ordering {
69        if FIXED {
70            self.str.cmp(&other.str)
71        } else {
72            self.str[..self.len()].cmp(&other.str[..other.len()])
73        }
74    }
75}
76
77// Why can’t this be derived from Ord?
78impl_for! {
79    PartialOrd:
80
81    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
82        Some(self.cmp(other))
83    }
84} */
85
86impl_for! {
87    <2> PartialOrd<StringletBase<SIZE2, FIXED2, LEN2, ALIGN2>>:
88
89    fn partial_cmp(&self, other: &StringletBase<SIZE2, FIXED2, LEN2, ALIGN2>) -> Option<Ordering> {
90        Some(if FIXED && FIXED2 {
91            self.str[..].cmp(&other.str[..])
92        } else if FIXED {
93            self.str[..].cmp(&other.str[..other.len()])
94        } else {
95            self.str[..self.len()].cmp(&other.str[..other.len()])
96        })
97    }
98}
99
100impl_for! {
101    <'a, 2> PartialOrd<&'a StringletBase<SIZE2, FIXED2, LEN2, ALIGN2>>:
102
103    fn partial_cmp(&self, other: &&'a StringletBase<SIZE2, FIXED2, LEN2, ALIGN2>) -> Option<Ordering> {
104        self.partial_cmp(*other)
105    }
106}
107
108// Needed where explicitly requested, e.g. BTreeMap key
109impl_for! {
110    Ord:
111
112    fn cmp(&self, other: &Self) -> Ordering {
113        // Safe to unwrap, as we always return Some.
114        self.partial_cmp(other).unwrap()
115    }
116}
117
118#[cfg(test)]
119mod tests {
120    use super::*;
121
122    #[test]
123    fn test_eq() {
124        macro_rules! assert_eq_all {
125            ($a:expr) => {};
126            ($a:expr, $b:expr $(, $($rest:tt)*)?) => {
127                assert_eq!($a, $b);
128                assert_eq_all!($b $(, $($rest)*)?)
129            };
130        }
131
132        let s_x_1 = VarStringlet::<1>::from("x");
133        let s_x_2 = VarStringlet::<1>::from("x");
134        let s_y = VarStringlet::<1>::from("y");
135        let s2_x = VarStringlet::<2>::from("x");
136        let s2_y = VarStringlet::<2>::from("y");
137        let s2_xy = VarStringlet::<2>::from("xy");
138
139        let f_x_1 = Stringlet::<1>::from("x");
140        let f_x_2 = Stringlet::<1>::from("x");
141        let f_y = Stringlet::<1>::from("y");
142        let f2_xy = Stringlet::<2>::from("xy");
143
144        assert_eq_all!(s_x_1, s_x_2, s2_x, f_x_1, f_x_2);
145        assert_eq_all!(s_y, s2_y, f_y);
146        assert_eq!(s2_xy, f2_xy);
147
148        assert_ne!(s_x_1, s_y);
149        assert_ne!(s_x_1, s2_y);
150        assert_ne!(s2_y, s_x_1);
151        assert_ne!(s_x_1, s2_xy);
152        assert_ne!(s2_xy, s_x_1);
153
154        assert_ne!(s_x_1, f_y);
155        assert_ne!(s_x_1, f2_xy);
156        assert_ne!(f2_xy, s_x_1);
157    }
158}