1use super::{from_raw_parts, memchr};
4use crate::ascii;
5use crate::cmp::{self, BytewiseEq, Ordering};
6use crate::intrinsics::compare_bytes;
7use crate::marker::Destruct;
8use crate::mem::{SizedTypeProperties, transmute_copy};
9use crate::num::NonZero;
10use crate::ops::ControlFlow;
11
12#[stable(feature = "rust1", since = "1.0.0")]
13#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
14const impl<T, U> PartialEq<[U]> for [T]
15where
16 T: [const] PartialEq<U>,
17{
18 #[inline]
19 #[ferrocene::prevalidated]
20 fn eq(&self, other: &[U]) -> bool {
21 let len = self.len();
22 if len == other.len() {
23 unsafe { SlicePartialEq::equal_same_length(self.as_ptr(), other.as_ptr(), len) }
26 } else {
27 false
28 }
29 }
30}
31
32#[stable(feature = "rust1", since = "1.0.0")]
33#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
34const impl<T: [const] Eq> Eq for [T] {}
35
36#[stable(feature = "rust1", since = "1.0.0")]
38#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
39const impl<T: [const] Ord> Ord for [T] {
40 #[ferrocene::prevalidated]
41 fn cmp(&self, other: &[T]) -> Ordering {
42 SliceOrd::compare(self, other)
43 }
44}
45
46#[inline]
47const fn as_underlying(x: ControlFlow<bool>) -> u8 {
48 unsafe { crate::mem::transmute(x) }
55}
56
57#[stable(feature = "rust1", since = "1.0.0")]
59#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
60const impl<T: [const] PartialOrd> PartialOrd for [T] {
61 #[ferrocene::prevalidated]
62 #[inline]
63 fn partial_cmp(&self, other: &[T]) -> Option<Ordering> {
64 SlicePartialOrd::partial_compare(self, other)
65 }
66 #[inline]
67 fn lt(&self, other: &Self) -> bool {
68 as_underlying(self.__chaining_lt(other)) == 1
77 }
78 #[inline]
79 fn le(&self, other: &Self) -> bool {
80 as_underlying(self.__chaining_le(other)) != 0
81 }
82 #[inline]
83 fn gt(&self, other: &Self) -> bool {
84 as_underlying(self.__chaining_gt(other)) == 1
85 }
86 #[inline]
87 fn ge(&self, other: &Self) -> bool {
88 as_underlying(self.__chaining_ge(other)) != 0
89 }
90 #[inline]
91 fn __chaining_lt(&self, other: &Self) -> ControlFlow<bool> {
92 SliceChain::chaining_lt(self, other)
93 }
94 #[inline]
95 fn __chaining_le(&self, other: &Self) -> ControlFlow<bool> {
96 SliceChain::chaining_le(self, other)
97 }
98 #[inline]
99 fn __chaining_gt(&self, other: &Self) -> ControlFlow<bool> {
100 SliceChain::chaining_gt(self, other)
101 }
102 #[inline]
103 fn __chaining_ge(&self, other: &Self) -> ControlFlow<bool> {
104 SliceChain::chaining_ge(self, other)
105 }
106}
107
108#[doc(hidden)]
109#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
111const trait SlicePartialEq<B> {
112 unsafe fn equal_same_length(lhs: *const Self, rhs: *const B, len: usize) -> bool;
115}
116
117#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
119const impl<A, B> SlicePartialEq<B> for A
120where
121 A: [const] PartialEq<B>,
122{
123 #[rustc_no_mir_inline]
128 #[ferrocene::prevalidated]
129 default unsafe fn equal_same_length(lhs: *const Self, rhs: *const B, len: usize) -> bool {
130 for idx in 0..len {
134 if unsafe { *lhs.add(idx) != *rhs.add(idx) } {
136 return false;
137 }
138 }
139
140 true
141 }
142}
143
144#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
147const impl<A, B> SlicePartialEq<B> for A
148where
149 A: [const] BytewiseEq<B>,
150{
151 #[inline]
152 #[ferrocene::prevalidated]
153 unsafe fn equal_same_length(lhs: *const Self, rhs: *const B, len: usize) -> bool {
154 unsafe {
158 let size = crate::intrinsics::unchecked_mul(len, Self::SIZE);
159 compare_bytes(lhs as _, rhs as _, size) == 0
160 }
161 }
162}
163
164#[doc(hidden)]
165#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
166const trait SlicePartialOrd: Sized {
168 fn partial_compare(left: &[Self], right: &[Self]) -> Option<Ordering>;
169}
170
171#[doc(hidden)]
172#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
173const trait SliceChain: Sized {
175 fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
176 fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
177 fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
178 fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow<bool>;
179}
180
181type AlwaysBreak<B> = ControlFlow<B, !>;
182
183#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
184const impl<A: [const] PartialOrd> SlicePartialOrd for A {
185 default fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
186 let elem_chain = const |a, b| match PartialOrd::partial_cmp(a, b) {
187 Some(Ordering::Equal) => ControlFlow::Continue(()),
188 non_eq => ControlFlow::Break(non_eq),
189 };
190
191 let len_chain = const |a: &_, b: &_| ControlFlow::Break(usize::partial_cmp(a, b));
192
193 let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain);
194 b
195 }
196}
197
198#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
199const impl<A: [const] PartialOrd> SliceChain for A {
200 default fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
201 chaining_impl(left, right, PartialOrd::__chaining_lt, usize::__chaining_lt)
202 }
203 default fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
204 chaining_impl(left, right, PartialOrd::__chaining_le, usize::__chaining_le)
205 }
206 default fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
207 chaining_impl(left, right, PartialOrd::__chaining_gt, usize::__chaining_gt)
208 }
209 default fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
210 chaining_impl(left, right, PartialOrd::__chaining_ge, usize::__chaining_ge)
211 }
212}
213
214#[ferrocene::prevalidated]
215#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
216#[inline]
217const fn chaining_impl<'l, 'r, A: PartialOrd, B, C>(
218 left: &'l [A],
219 right: &'r [A],
220 elem_chain: impl [const] Fn(&'l A, &'r A) -> ControlFlow<B> + [const] Destruct,
221 len_chain: impl for<'a> [const] FnOnce(&'a usize, &'a usize) -> ControlFlow<B, C> + [const] Destruct,
222) -> ControlFlow<B, C> {
223 let l = cmp::min(left.len(), right.len());
224
225 let lhs = &left[..l];
228 let rhs = &right[..l];
229
230 for i in 0..l {
231 elem_chain(&lhs[i], &rhs[i])?;
232 }
233
234 len_chain(&left.len(), &right.len())
235}
236
237#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
251const impl<A: [const] AlwaysApplicableOrd> SlicePartialOrd for A {
252 fn partial_compare(left: &[A], right: &[A]) -> Option<Ordering> {
253 Some(SliceOrd::compare(left, right))
254 }
255}
256
257#[rustc_specialization_trait]
258#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
259const trait AlwaysApplicableOrd: [const] SliceOrd + [const] Ord {}
260
261macro_rules! always_applicable_ord {
262 ($([$($p:tt)*] $t:ty,)*) => {
263 $(impl<$($p)*> AlwaysApplicableOrd for $t {})*
264 }
265}
266
267always_applicable_ord! {
268 [] u8, [] u16, [] u32, [] u64, [] u128, [] usize,
269 [] i8, [] i16, [] i32, [] i64, [] i128, [] isize,
270 [] bool, [] char,
271 [T: ?Sized] *const T, [T: ?Sized] *mut T,
272 [T: AlwaysApplicableOrd] &T,
273 [T: AlwaysApplicableOrd] &mut T,
274 [T: AlwaysApplicableOrd] Option<T>,
275}
276
277#[doc(hidden)]
278#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
279const trait SliceOrd: Sized {
281 fn compare(left: &[Self], right: &[Self]) -> Ordering;
282}
283
284#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
285const impl<A: [const] Ord> SliceOrd for A {
286 #[ferrocene::prevalidated]
287 default fn compare(left: &[Self], right: &[Self]) -> Ordering {
288 let elem_chain = const |a, b| match Ord::cmp(a, b) {
289 Ordering::Equal => ControlFlow::Continue(()),
290 non_eq => ControlFlow::Break(non_eq),
291 };
292
293 let len_chain = const |a: &_, b: &_| ControlFlow::Break(usize::cmp(a, b));
294
295 let AlwaysBreak::Break(b) = chaining_impl(left, right, elem_chain, len_chain);
296 b
297 }
298}
299
300#[rustc_specialization_trait]
308const unsafe trait UnsignedBytewiseOrd: [const] Ord {}
309
310#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
311const unsafe impl UnsignedBytewiseOrd for bool {}
312#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
313const unsafe impl UnsignedBytewiseOrd for u8 {}
314#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
315const unsafe impl UnsignedBytewiseOrd for NonZero<u8> {}
316#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
317const unsafe impl UnsignedBytewiseOrd for Option<NonZero<u8>> {}
318#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
319const unsafe impl UnsignedBytewiseOrd for ascii::Char {}
320
321#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
324const impl<A: [const] Ord + [const] UnsignedBytewiseOrd> SliceOrd for A {
325 #[inline]
326 fn compare(left: &[Self], right: &[Self]) -> Ordering {
327 let diff = left.len() as isize - right.len() as isize;
330 let len = if left.len() < right.len() { left.len() } else { right.len() };
333 let left = left.as_ptr().cast();
334 let right = right.as_ptr().cast();
335 let mut order = unsafe { compare_bytes(left, right, len) as isize };
341 if order == 0 {
342 order = diff;
343 }
344 order.cmp(&0)
345 }
346}
347
348#[rustc_const_unstable(feature = "const_cmp", issue = "143800")]
351const impl<A: [const] PartialOrd + [const] UnsignedBytewiseOrd> SliceChain for A {
352 #[inline]
353 fn chaining_lt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
354 match SliceOrd::compare(left, right) {
355 Ordering::Equal => ControlFlow::Continue(()),
356 ne => ControlFlow::Break(ne.is_lt()),
357 }
358 }
359 #[inline]
360 fn chaining_le(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
361 match SliceOrd::compare(left, right) {
362 Ordering::Equal => ControlFlow::Continue(()),
363 ne => ControlFlow::Break(ne.is_le()),
364 }
365 }
366 #[inline]
367 fn chaining_gt(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
368 match SliceOrd::compare(left, right) {
369 Ordering::Equal => ControlFlow::Continue(()),
370 ne => ControlFlow::Break(ne.is_gt()),
371 }
372 }
373 #[inline]
374 fn chaining_ge(left: &[Self], right: &[Self]) -> ControlFlow<bool> {
375 match SliceOrd::compare(left, right) {
376 Ordering::Equal => ControlFlow::Continue(()),
377 ne => ControlFlow::Break(ne.is_ge()),
378 }
379 }
380}
381
382pub(super) trait SliceContains: Sized {
383 fn slice_contains(&self, x: &[Self]) -> bool;
384}
385
386impl<T> SliceContains for T
387where
388 T: PartialEq,
389{
390 #[expect(clippy::manual_contains, reason = "implements slice_contains")]
391 default fn slice_contains(&self, x: &[Self]) -> bool {
392 x.iter().any(|y| *y == *self)
393 }
394}
395
396impl<T: BytewiseEq> SliceContains for T {
397 #[inline]
398 #[expect(clippy::manual_contains, reason = "implements slice_contains")]
399 default fn slice_contains(&self, x: &[Self]) -> bool {
400 if size_of::<T>() == 1 {
401 let (byte, bytes) = unsafe {
405 (transmute_copy::<T, u8>(self), from_raw_parts(x.as_ptr().cast::<u8>(), x.len()))
406 };
407 memchr::memchr(byte, bytes).is_some()
408 } else {
409 x.iter().any(|y| *y == *self)
410 }
411 }
412}
413
414macro_rules! impl_slice_contains {
415 ($($t:ty),*) => {
416 $(
417 impl SliceContains for $t {
418 #[inline]
419 fn slice_contains(&self, arr: &[$t]) -> bool {
420 const LANE_COUNT: usize = 4 * (128 / (size_of::<$t>() * 8));
423 let mut chunks = arr.chunks_exact(LANE_COUNT);
425 for chunk in &mut chunks {
426 if chunk.iter().fold(false, |acc, x| acc | (*x == *self)) {
427 return true;
428 }
429 }
430 return chunks.remainder().iter().any(|x| *x == *self);
432 }
433 }
434 )*
435 };
436}
437
438impl_slice_contains!(u16, u32, u64, i16, i32, i64, f32, f64, usize, isize, char);