1use core::cmp::Ordering;
2
3#[inline]
16#[must_use]
17pub fn casecmp(left: &[u8], right: &[u8]) -> Ordering {
18 let left = left.iter().map(u8::to_ascii_lowercase);
19 let right = right.iter().map(u8::to_ascii_lowercase);
20 left.cmp(right)
21}
22
23#[inline]
35#[must_use]
36pub fn case_eq(left: &[u8], right: &[u8]) -> bool {
37 left.eq_ignore_ascii_case(right)
38}
39
40#[cfg(test)]
41mod tests {
42 use core::cmp::Ordering;
43
44 use super::{case_eq, casecmp};
45
46 #[test]
47 fn empty_string() {
48 assert!(case_eq(b"", b""));
49 assert_eq!(casecmp(b"", b""), Ordering::Equal);
50
51 assert!(!case_eq(b"", b"rake"));
52 assert_eq!(casecmp(b"", b"rake"), Ordering::Less);
53
54 assert!(!case_eq(b"rake", b""));
55 assert_eq!(casecmp(b"rake", b""), Ordering::Greater);
56 }
57
58 #[test]
59 fn unicode_replacement_character() {
60 assert!(case_eq("\u{FFFD}".as_bytes(), "\u{FFFD}".as_bytes()));
61 assert_eq!(
62 casecmp("\u{FFFD}".as_bytes(), "\u{FFFD}".as_bytes()),
63 Ordering::Equal
64 );
65
66 assert_eq!(
67 casecmp("\u{FFFD}".as_bytes(), "\u{FFFD}yam".as_bytes()),
68 Ordering::Less
69 );
70 assert_eq!(
71 casecmp("\u{FFFD}yam".as_bytes(), "\u{FFFD}".as_bytes()),
72 Ordering::Greater
73 );
74 }
75
76 #[test]
77 fn compares_symbols_without_regard_to_case() {
78 assert!(!case_eq(b"abcdef", b"abcde"));
79 assert!(case_eq(b"aBcDeF", b"abcdef"));
80 assert!(!case_eq(b"abcdef", b"abcdefg"));
81 assert!(case_eq(b"abcdef", b"ABCDEF"));
82
83 assert_eq!(casecmp(b"abcdef", b"abcde"), Ordering::Greater);
84 assert_eq!(casecmp(b"aBcDeF", b"abcdef"), Ordering::Equal);
85 assert_eq!(casecmp(b"abcdef", b"abcdefg"), Ordering::Less);
86 assert_eq!(casecmp(b"abcdef", b"ABCDEF"), Ordering::Equal);
87
88 assert_eq!(casecmp(b"abcdef", b"abcde") as i32, 1);
89 assert_eq!(casecmp(b"aBcDeF", b"abcdef") as i32, 0);
90 assert_eq!(casecmp(b"abcdef", b"abcdefg") as i32, -1);
91 assert_eq!(casecmp(b"abcdef", b"ABCDEF") as i32, 0);
92 assert_eq!(casecmp(b"abcdef", b"abcde") as i32, 1);
93 }
94
95 #[test]
96 fn non_ascii_chars_that_are_not_fold_eq_are_not_eq() {
97 let upper_a_tilde = b"\xC3";
99 let upper_a_umlaut = b"\xC4";
100 let lower_a_tilde = b"\xE3";
101 let lower_a_umlaut = b"\xE4";
102
103 assert!(!case_eq(lower_a_tilde, lower_a_umlaut));
112 assert!(!case_eq(lower_a_umlaut, lower_a_tilde));
113 assert!(!case_eq(upper_a_tilde, upper_a_umlaut));
114 assert!(!case_eq(upper_a_umlaut, upper_a_tilde));
115
116 assert_ne!(casecmp(lower_a_tilde, lower_a_umlaut), Ordering::Equal);
117 assert_ne!(casecmp(lower_a_umlaut, lower_a_tilde), Ordering::Equal);
118 assert_ne!(casecmp(upper_a_tilde, upper_a_umlaut), Ordering::Equal);
119 assert_ne!(casecmp(upper_a_umlaut, upper_a_tilde), Ordering::Equal);
120
121 let upper_a_tilde = "Ã".as_bytes();
123 let lower_a_tilde = "ã".as_bytes();
124 let upper_a_umlaut = "Ä".as_bytes();
125 let lower_a_umlaut = "ä".as_bytes();
126
127 assert!(!case_eq(lower_a_tilde, lower_a_umlaut));
136 assert!(!case_eq(lower_a_umlaut, lower_a_tilde));
137 assert!(!case_eq(upper_a_tilde, upper_a_umlaut));
138 assert!(!case_eq(upper_a_umlaut, upper_a_tilde));
139
140 assert_ne!(casecmp(lower_a_tilde, lower_a_umlaut), Ordering::Equal);
141 assert_ne!(casecmp(lower_a_umlaut, lower_a_tilde), Ordering::Equal);
142 assert_ne!(casecmp(upper_a_tilde, upper_a_umlaut), Ordering::Equal);
143 assert_ne!(casecmp(upper_a_umlaut, upper_a_tilde), Ordering::Equal);
144 }
145
146 #[test]
147 fn doesent_do_case_mapping_for_non_ascii_chars() {
148 let upper_a_tilde = b"\xC3";
150 let upper_a_umlaut = b"\xC4";
151 let lower_a_tilde = b"\xE3";
152 let lower_a_umlaut = b"\xE4";
153
154 assert!(!case_eq(upper_a_tilde, lower_a_tilde));
163 assert!(!case_eq(upper_a_umlaut, lower_a_umlaut));
164 assert!(!case_eq(lower_a_tilde, upper_a_tilde));
165 assert!(!case_eq(lower_a_umlaut, upper_a_umlaut));
166
167 assert_eq!(casecmp(upper_a_tilde, lower_a_tilde), Ordering::Less);
168 assert_eq!(casecmp(upper_a_umlaut, lower_a_umlaut), Ordering::Less);
169 assert_eq!(casecmp(lower_a_tilde, upper_a_tilde), Ordering::Greater);
170 assert_eq!(casecmp(lower_a_umlaut, upper_a_umlaut), Ordering::Greater);
171
172 assert_eq!(casecmp(upper_a_tilde, lower_a_tilde) as i32, -1);
173 assert_eq!(casecmp(upper_a_umlaut, lower_a_umlaut) as i32, -1);
174 assert_eq!(casecmp(lower_a_tilde, upper_a_tilde) as i32, 1);
175 assert_eq!(casecmp(lower_a_umlaut, upper_a_umlaut) as i32, 1);
176
177 let upper_a_tilde = "Ã".as_bytes();
179 let lower_a_tilde = "ã".as_bytes();
180 let upper_a_umlaut = "Ä".as_bytes();
181 let lower_a_umlaut = "ä".as_bytes();
182
183 assert!(!case_eq(upper_a_tilde, lower_a_tilde));
192 assert!(!case_eq(upper_a_umlaut, lower_a_umlaut));
193 assert!(!case_eq(lower_a_tilde, upper_a_tilde));
194 assert!(!case_eq(lower_a_umlaut, upper_a_umlaut));
195
196 assert_eq!(casecmp(upper_a_tilde, lower_a_tilde), Ordering::Less);
197 assert_eq!(casecmp(upper_a_umlaut, lower_a_umlaut), Ordering::Less);
198 assert_eq!(casecmp(lower_a_tilde, upper_a_tilde), Ordering::Greater);
199 assert_eq!(casecmp(lower_a_umlaut, upper_a_umlaut), Ordering::Greater);
200
201 assert_eq!(casecmp(upper_a_tilde, lower_a_tilde) as i32, -1);
202 assert_eq!(casecmp(upper_a_umlaut, lower_a_umlaut) as i32, -1);
203 assert_eq!(casecmp(lower_a_tilde, upper_a_tilde) as i32, 1);
204 assert_eq!(casecmp(lower_a_umlaut, upper_a_umlaut) as i32, 1);
205 }
206
207 #[test]
208 fn exhaustive() {
209 let lower = 'a'..='z';
210 let upper = 'A'..='Z';
211 let mut l_buf = [0; 4];
212 let mut r_buf = [0; 4];
213 for (left, right) in lower.zip(upper) {
214 let left = left.encode_utf8(&mut l_buf);
215 let right = right.encode_utf8(&mut r_buf);
216 assert_eq!(casecmp(left.as_bytes(), right.as_bytes()), Ordering::Equal);
217 assert_eq!(casecmp(right.as_bytes(), left.as_bytes()), Ordering::Equal);
218 }
219 }
220}