|
3 | 3 | use super::{from_raw_parts, memchr};
|
4 | 4 | use crate::cmp::{self, BytewiseEq, Ordering};
|
5 | 5 | use crate::intrinsics::compare_bytes;
|
6 |
| -use crate::mem; |
| 6 | +use crate::num::NonZero; |
| 7 | +use crate::{ascii, mem}; |
7 | 8 |
|
8 | 9 | #[stable(feature = "rust1", since = "1.0.0")]
|
9 | 10 | impl<T, U> PartialEq<[U]> for [T]
|
@@ -182,19 +183,41 @@ impl<A: Ord> SliceOrd for A {
|
182 | 183 | }
|
183 | 184 | }
|
184 | 185 |
|
185 |
| -// `compare_bytes` compares a sequence of unsigned bytes lexicographically. |
186 |
| -// this matches the order we want for [u8], but no others (not even [i8]). |
187 |
| -impl SliceOrd for u8 { |
| 186 | +/// Marks that a type should be treated as an unsigned byte for comparisons. |
| 187 | +/// |
| 188 | +/// # Safety |
| 189 | +/// * The type must be readable as an `u8`, meaning it has to have the same |
| 190 | +/// layout as `u8` and always be initialized. |
| 191 | +/// * For every `x` and `y` of this type, `Ord(x, y)` must return the same |
| 192 | +/// value as `Ord::cmp(transmute::<_, u8>(x), transmute::<_, u8>(y))`. |
| 193 | +#[rustc_specialization_trait] |
| 194 | +unsafe trait UnsignedBytewiseOrd {} |
| 195 | + |
| 196 | +unsafe impl UnsignedBytewiseOrd for bool {} |
| 197 | +unsafe impl UnsignedBytewiseOrd for u8 {} |
| 198 | +unsafe impl UnsignedBytewiseOrd for NonZero<u8> {} |
| 199 | +unsafe impl UnsignedBytewiseOrd for Option<NonZero<u8>> {} |
| 200 | +unsafe impl UnsignedBytewiseOrd for ascii::Char {} |
| 201 | + |
| 202 | +// `compare_bytes` compares a sequence of unsigned bytes lexicographically, so |
| 203 | +// use it if the requirements for `UnsignedBytewiseOrd` are fulfilled. |
| 204 | +impl<A: Ord + UnsignedBytewiseOrd> SliceOrd for A { |
188 | 205 | #[inline]
|
189 | 206 | fn compare(left: &[Self], right: &[Self]) -> Ordering {
|
190 |
| - // Since the length of a slice is always less than or equal to isize::MAX, this never underflows. |
| 207 | + // Since the length of a slice is always less than or equal to |
| 208 | + // isize::MAX, this never underflows. |
191 | 209 | let diff = left.len() as isize - right.len() as isize;
|
192 |
| - // This comparison gets optimized away (on x86_64 and ARM) because the subtraction updates flags. |
| 210 | + // This comparison gets optimized away (on x86_64 and ARM) because the |
| 211 | + // subtraction updates flags. |
193 | 212 | let len = if left.len() < right.len() { left.len() } else { right.len() };
|
194 |
| - // SAFETY: `left` and `right` are references and are thus guaranteed to be valid. |
195 |
| - // We use the minimum of both lengths which guarantees that both regions are |
196 |
| - // valid for reads in that interval. |
197 |
| - let mut order = unsafe { compare_bytes(left.as_ptr(), right.as_ptr(), len) as isize }; |
| 213 | + let left = left.as_ptr().cast(); |
| 214 | + let right = right.as_ptr().cast(); |
| 215 | + // SAFETY: `left` and `right` are references and are thus guaranteed to |
| 216 | + // be valid. `UnsignedBytewiseOrd` is only implemented for types that |
| 217 | + // are valid u8s and can be compared the same way. We use the minimum |
| 218 | + // of both lengths which guarantees that both regions are valid for |
| 219 | + // reads in that interval. |
| 220 | + let mut order = unsafe { compare_bytes(left, right, len) as isize }; |
198 | 221 | if order == 0 {
|
199 | 222 | order = diff;
|
200 | 223 | }
|
|
0 commit comments