1#[cfg(feature = "rust_1_46")]
27#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_46")))]
28#[inline]
29pub const fn str_eq(left: &str, right: &str) -> bool {
30 u8_slice_eq(left.as_bytes(), right.as_bytes())
31}
32
33#[cfg(feature = "rust_1_46")]
57#[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_46")))]
58#[inline]
59pub const fn u8_slice_eq(left: &[u8], right: &[u8]) -> bool {
60 if left.len() != right.len() {
61 return false;
62 }
63
64 let mut i = 0;
65 while i != left.len() {
66 if left[i] != right[i] {
67 return false;
68 }
69 i += 1;
70 }
71
72 true
73}
74
75#[cfg(feature = "rust_1_46")]
76pub use slice_cmp::{str_cmp, u8_slice_cmp};
77
78#[cfg(feature = "rust_1_46")]
79mod slice_cmp {
80 use core::cmp::Ordering;
81
82 const LESS: u8 = 0;
83 const GREATER: u8 = 1;
84 const EQUAL: u8 = 2;
85
86 macro_rules! ret_if_ne {
87 ($left:expr, $right:expr) => {{
88 let l = $left;
89 let r = $right;
90 if l != r {
91 return (l > r) as u8;
92 }
93 }};
94 }
95
96 const fn to_ordering(n: u8) -> Ordering {
97 match n {
98 LESS => Ordering::Less,
99 GREATER => Ordering::Greater,
100 _ => Ordering::Equal,
101 }
102 }
103
104 #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_46")))]
130 #[inline]
131 pub const fn str_cmp(left: &str, right: &str) -> Ordering {
132 const fn str_cmp_inner(left: &[u8], right: &[u8]) -> u8 {
133 let left_len = left.len();
134 let right_len = right.len();
135 let (min_len, on_ne) = if left_len < right_len {
136 (left_len, LESS)
137 } else {
138 (right_len, GREATER)
139 };
140
141 let mut i = 0;
142 while i < min_len {
143 ret_if_ne! {left[i], right[i]}
144 i += 1;
145 }
146
147 if left_len == right_len {
148 EQUAL
149 } else {
150 on_ne
151 }
152 }
153
154 to_ordering(str_cmp_inner(left.as_bytes(), right.as_bytes()))
155 }
156
157 #[cfg_attr(feature = "docsrs", doc(cfg(feature = "rust_1_46")))]
182 #[inline]
183 pub const fn u8_slice_cmp(left: &[u8], right: &[u8]) -> Ordering {
184 const fn u8_slice_cmp_inner(left: &[u8], right: &[u8]) -> u8 {
185 let left_len = left.len();
186
187 ret_if_ne! {left_len, right.len()}
188
189 let mut i = 0;
190 while i < left_len {
191 ret_if_ne! {left[i], right[i]}
192 i += 1;
193 }
194
195 EQUAL
196 }
197
198 to_ordering(u8_slice_cmp_inner(left, right))
199 }
200}
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205
206 #[test]
207 #[cfg(feature = "rust_1_46")]
208 fn slice_eq_test() {
209 assert!(u8_slice_eq(&[], &[]));
210 assert!(!u8_slice_eq(&[], &[0]));
211 assert!(!u8_slice_eq(&[0], &[]));
212 assert!(u8_slice_eq(&[0], &[0]));
213 assert!(!u8_slice_eq(&[0], &[1]));
214 assert!(!u8_slice_eq(&[1], &[0]));
215 assert!(!u8_slice_eq(&[0], &[0, 1]));
216 assert!(!u8_slice_eq(&[0, 1], &[0]));
217 assert!(u8_slice_eq(&[0, 1], &[0, 1]));
218 assert!(!u8_slice_eq(&[0, 1], &[0, 2]));
219 }
220
221 #[test]
222 #[cfg(feature = "rust_1_46")]
223 fn str_eq_test() {
224 assert!(str_eq("", ""));
225 assert!(!str_eq("", "0"));
226 assert!(!str_eq("0", ""));
227 assert!(str_eq("0", "0"));
228 assert!(!str_eq("0", "1"));
229 assert!(!str_eq("1", "0"));
230 assert!(!str_eq("0", "0, 1"));
231 assert!(!str_eq("0, 1", "0"));
232 assert!(!str_eq("0, 1", "1"));
233 assert!(str_eq("0, 1", "0, 1"));
234 assert!(!str_eq("0, 1", "0, 2"));
235 }
236
237 #[test]
238 #[cfg(feature = "rust_1_46")]
239 fn slice_cmp_test() {
240 use core::cmp::{
241 Ord,
242 Ordering::{Equal, Greater, Less},
243 };
244
245 macro_rules! assert_s_cmp {
246 ($left:expr, $right:expr, $expected:expr) => {
247 assert_eq!(u8_slice_cmp($left, $right), $expected);
248 assert_eq!(<[u8]>::cmp($left, $right), $expected);
249
250 assert_eq!(u8_slice_cmp($right, $left), $expected.reverse());
251 assert_eq!(<[u8]>::cmp($right, $left), $expected.reverse());
252 };
253 }
254
255 assert_s_cmp!(&[], &[], Equal);
256 assert_s_cmp!(&[], &[0], Less);
257 assert_s_cmp!(&[0], &[], Greater);
258 assert_s_cmp!(&[0], &[0], Equal);
259 assert_s_cmp!(&[0], &[1], Less);
260 assert_s_cmp!(&[0], &[0, 1], Less);
261 assert_s_cmp!(&[0, 1], &[0, 1], Equal);
262 assert_s_cmp!(&[0, 1], &[0, 2], Less);
263 }
264
265 #[test]
266 #[cfg(feature = "rust_1_46")]
267 fn str_cmp_test() {
268 use core::cmp::{
269 Ord,
270 Ordering::{Equal, Greater, Less},
271 };
272
273 macro_rules! assert_s_cmp {
274 ($left:expr, $right:expr, $expected:expr) => {
275 assert_eq!(str_cmp($left, $right), $expected, "A");
276 assert_eq!($left.cmp($right), $expected, "B");
277
278 assert_eq!(str_cmp($left, $left), Equal);
279 assert_eq!(str_cmp($right, $right), Equal);
280
281 assert_eq!(str_cmp($right, $left), $expected.reverse(), "cmp");
282 assert_eq!($right.cmp($left), $expected.reverse(), "cmp");
283 };
284 }
285
286 assert_s_cmp!("0", "", Greater);
287 assert_s_cmp!("0", "1", Less);
288 assert_s_cmp!("0", "01", Less);
289 assert_s_cmp!("1", "01", Greater);
290 assert_s_cmp!("099999", "12", Less);
291 assert_s_cmp!("111111", "12", Less);
292 assert_s_cmp!("120", "12", Greater);
293 assert_s_cmp!("199999", "12", Greater);
294 assert_s_cmp!("299999", "12", Greater);
295 assert_s_cmp!("01", "02", Less);
296 }
297}