1 | //! Indexing implementations for `[T]`. |
2 | |
3 | use crate::panic::const_panic; |
4 | use crate::ub_checks::assert_unsafe_precondition; |
5 | use crate::{ops, range}; |
6 | |
7 | #[stable (feature = "rust1" , since = "1.0.0" )] |
8 | impl<T, I> ops::Index<I> for [T] |
9 | where |
10 | I: SliceIndex<[T]>, |
11 | { |
12 | type Output = I::Output; |
13 | |
14 | #[inline (always)] |
15 | fn index(&self, index: I) -> &I::Output { |
16 | index.index(self) |
17 | } |
18 | } |
19 | |
20 | #[stable (feature = "rust1" , since = "1.0.0" )] |
21 | impl<T, I> ops::IndexMut<I> for [T] |
22 | where |
23 | I: SliceIndex<[T]>, |
24 | { |
25 | #[inline (always)] |
26 | fn index_mut(&mut self, index: I) -> &mut I::Output { |
27 | index.index_mut(self) |
28 | } |
29 | } |
30 | |
31 | #[cfg_attr (not(feature = "panic_immediate_abort" ), inline(never), cold)] |
32 | #[cfg_attr (feature = "panic_immediate_abort" , inline)] |
33 | #[track_caller ] |
34 | const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { |
35 | const_panic!( |
36 | "slice start index is out of range for slice" , |
37 | "range start index {index} out of range for slice of length {len}" , |
38 | index: usize, |
39 | len: usize, |
40 | ) |
41 | } |
42 | |
43 | #[cfg_attr (not(feature = "panic_immediate_abort" ), inline(never), cold)] |
44 | #[cfg_attr (feature = "panic_immediate_abort" , inline)] |
45 | #[track_caller ] |
46 | const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { |
47 | const_panic!( |
48 | "slice end index is out of range for slice" , |
49 | "range end index {index} out of range for slice of length {len}" , |
50 | index: usize, |
51 | len: usize, |
52 | ) |
53 | } |
54 | |
55 | #[cfg_attr (not(feature = "panic_immediate_abort" ), inline(never), cold)] |
56 | #[cfg_attr (feature = "panic_immediate_abort" , inline)] |
57 | #[track_caller ] |
58 | const fn slice_index_order_fail(index: usize, end: usize) -> ! { |
59 | const_panic!( |
60 | "slice index start is larger than end" , |
61 | "slice index starts at {index} but ends at {end}" , |
62 | index: usize, |
63 | end: usize, |
64 | ) |
65 | } |
66 | |
67 | #[cfg_attr (not(feature = "panic_immediate_abort" ), inline(never), cold)] |
68 | #[cfg_attr (feature = "panic_immediate_abort" , inline)] |
69 | #[track_caller ] |
70 | const fn slice_start_index_overflow_fail() -> ! { |
71 | panic!("attempted to index slice from after maximum usize" ); |
72 | } |
73 | |
74 | #[cfg_attr (not(feature = "panic_immediate_abort" ), inline(never), cold)] |
75 | #[cfg_attr (feature = "panic_immediate_abort" , inline)] |
76 | #[track_caller ] |
77 | const fn slice_end_index_overflow_fail() -> ! { |
78 | panic!("attempted to index slice up to maximum usize" ); |
79 | } |
80 | |
81 | // The UbChecks are great for catching bugs in the unsafe methods, but including |
82 | // them in safe indexing is unnecessary and hurts inlining and debug runtime perf. |
83 | // Both the safe and unsafe public methods share these helpers, |
84 | // which use intrinsics directly to get *no* extra checks. |
85 | |
86 | #[inline (always)] |
87 | const unsafe fn get_noubcheck<T>(ptr: *const [T], index: usize) -> *const T { |
88 | let ptr: *const T = ptr as *const T; |
89 | // SAFETY: The caller already checked these preconditions |
90 | unsafe { crate::intrinsics::offset(dst:ptr, offset:index) } |
91 | } |
92 | |
93 | #[inline (always)] |
94 | const unsafe fn get_mut_noubcheck<T>(ptr: *mut [T], index: usize) -> *mut T { |
95 | let ptr: *mut T = ptr as *mut T; |
96 | // SAFETY: The caller already checked these preconditions |
97 | unsafe { crate::intrinsics::offset(dst:ptr, offset:index) } |
98 | } |
99 | |
100 | #[inline (always)] |
101 | const unsafe fn get_offset_len_noubcheck<T>( |
102 | ptr: *const [T], |
103 | offset: usize, |
104 | len: usize, |
105 | ) -> *const [T] { |
106 | // SAFETY: The caller already checked these preconditions |
107 | let ptr: *const T = unsafe { get_noubcheck(ptr, index:offset) }; |
108 | crate::intrinsics::aggregate_raw_ptr(data:ptr, meta:len) |
109 | } |
110 | |
111 | #[inline (always)] |
112 | const unsafe fn get_offset_len_mut_noubcheck<T>( |
113 | ptr: *mut [T], |
114 | offset: usize, |
115 | len: usize, |
116 | ) -> *mut [T] { |
117 | // SAFETY: The caller already checked these preconditions |
118 | let ptr: *mut T = unsafe { get_mut_noubcheck(ptr, index:offset) }; |
119 | crate::intrinsics::aggregate_raw_ptr(data:ptr, meta:len) |
120 | } |
121 | |
122 | mod private_slice_index { |
123 | use super::{ops, range}; |
124 | |
125 | #[stable (feature = "slice_get_slice" , since = "1.28.0" )] |
126 | pub trait Sealed {} |
127 | |
128 | #[stable (feature = "slice_get_slice" , since = "1.28.0" )] |
129 | impl Sealed for usize {} |
130 | #[stable (feature = "slice_get_slice" , since = "1.28.0" )] |
131 | impl Sealed for ops::Range<usize> {} |
132 | #[stable (feature = "slice_get_slice" , since = "1.28.0" )] |
133 | impl Sealed for ops::RangeTo<usize> {} |
134 | #[stable (feature = "slice_get_slice" , since = "1.28.0" )] |
135 | impl Sealed for ops::RangeFrom<usize> {} |
136 | #[stable (feature = "slice_get_slice" , since = "1.28.0" )] |
137 | impl Sealed for ops::RangeFull {} |
138 | #[stable (feature = "slice_get_slice" , since = "1.28.0" )] |
139 | impl Sealed for ops::RangeInclusive<usize> {} |
140 | #[stable (feature = "slice_get_slice" , since = "1.28.0" )] |
141 | impl Sealed for ops::RangeToInclusive<usize> {} |
142 | #[stable (feature = "slice_index_with_ops_bound_pair" , since = "1.53.0" )] |
143 | impl Sealed for (ops::Bound<usize>, ops::Bound<usize>) {} |
144 | |
145 | #[unstable (feature = "new_range_api" , issue = "125687" )] |
146 | impl Sealed for range::Range<usize> {} |
147 | #[unstable (feature = "new_range_api" , issue = "125687" )] |
148 | impl Sealed for range::RangeInclusive<usize> {} |
149 | #[unstable (feature = "new_range_api" , issue = "125687" )] |
150 | impl Sealed for range::RangeFrom<usize> {} |
151 | |
152 | impl Sealed for ops::IndexRange {} |
153 | } |
154 | |
155 | /// A helper trait used for indexing operations. |
156 | /// |
157 | /// Implementations of this trait have to promise that if the argument |
158 | /// to `get_unchecked(_mut)` is a safe reference, then so is the result. |
159 | #[stable (feature = "slice_get_slice" , since = "1.28.0" )] |
160 | #[rustc_diagnostic_item = "SliceIndex" ] |
161 | #[rustc_on_unimplemented ( |
162 | on(T = "str" , label = "string indices are ranges of `usize`" ,), |
163 | on( |
164 | all(any(T = "str" , T = "&str" , T = "alloc::string::String" ), _Self = "{integer}" ), |
165 | note = "you can use `.chars().nth()` or `.bytes().nth()` \n\ |
166 | for more information, see chapter 8 in The Book: \ |
167 | <https://doc.rust-lang.org/book/ch08-02-strings.html#indexing-into-strings>" |
168 | ), |
169 | message = "the type `{T}` cannot be indexed by `{Self}`" , |
170 | label = "slice indices are of type `usize` or ranges of `usize`" |
171 | )] |
172 | pub unsafe trait SliceIndex<T: ?Sized>: private_slice_index::Sealed { |
173 | /// The output type returned by methods. |
174 | #[stable (feature = "slice_get_slice" , since = "1.28.0" )] |
175 | type Output: ?Sized; |
176 | |
177 | /// Returns a shared reference to the output at this location, if in |
178 | /// bounds. |
179 | #[unstable (feature = "slice_index_methods" , issue = "none" )] |
180 | fn get(self, slice: &T) -> Option<&Self::Output>; |
181 | |
182 | /// Returns a mutable reference to the output at this location, if in |
183 | /// bounds. |
184 | #[unstable (feature = "slice_index_methods" , issue = "none" )] |
185 | fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>; |
186 | |
187 | /// Returns a pointer to the output at this location, without |
188 | /// performing any bounds checking. |
189 | /// |
190 | /// Calling this method with an out-of-bounds index or a dangling `slice` pointer |
191 | /// is *[undefined behavior]* even if the resulting pointer is not used. |
192 | /// |
193 | /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html |
194 | #[unstable (feature = "slice_index_methods" , issue = "none" )] |
195 | unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; |
196 | |
197 | /// Returns a mutable pointer to the output at this location, without |
198 | /// performing any bounds checking. |
199 | /// |
200 | /// Calling this method with an out-of-bounds index or a dangling `slice` pointer |
201 | /// is *[undefined behavior]* even if the resulting pointer is not used. |
202 | /// |
203 | /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html |
204 | #[unstable (feature = "slice_index_methods" , issue = "none" )] |
205 | unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output; |
206 | |
207 | /// Returns a shared reference to the output at this location, panicking |
208 | /// if out of bounds. |
209 | #[unstable (feature = "slice_index_methods" , issue = "none" )] |
210 | #[track_caller ] |
211 | fn index(self, slice: &T) -> &Self::Output; |
212 | |
213 | /// Returns a mutable reference to the output at this location, panicking |
214 | /// if out of bounds. |
215 | #[unstable (feature = "slice_index_methods" , issue = "none" )] |
216 | #[track_caller ] |
217 | fn index_mut(self, slice: &mut T) -> &mut Self::Output; |
218 | } |
219 | |
220 | /// The methods `index` and `index_mut` panic if the index is out of bounds. |
221 | #[stable (feature = "slice_get_slice_impls" , since = "1.15.0" )] |
222 | unsafe impl<T> SliceIndex<[T]> for usize { |
223 | type Output = T; |
224 | |
225 | #[inline ] |
226 | fn get(self, slice: &[T]) -> Option<&T> { |
227 | // SAFETY: `self` is checked to be in bounds. |
228 | if self < slice.len() { unsafe { Some(&*get_noubcheck(slice, self)) } } else { None } |
229 | } |
230 | |
231 | #[inline ] |
232 | fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { |
233 | if self < slice.len() { |
234 | // SAFETY: `self` is checked to be in bounds. |
235 | unsafe { Some(&mut *get_mut_noubcheck(slice, self)) } |
236 | } else { |
237 | None |
238 | } |
239 | } |
240 | |
241 | #[inline ] |
242 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { |
243 | assert_unsafe_precondition!( |
244 | check_language_ub, |
245 | "slice::get_unchecked requires that the index is within the slice" , |
246 | (this: usize = self, len: usize = slice.len()) => this < len |
247 | ); |
248 | // SAFETY: the caller guarantees that `slice` is not dangling, so it |
249 | // cannot be longer than `isize::MAX`. They also guarantee that |
250 | // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, |
251 | // so the call to `add` is safe. |
252 | unsafe { |
253 | // Use intrinsics::assume instead of hint::assert_unchecked so that we don't check the |
254 | // precondition of this function twice. |
255 | crate::intrinsics::assume(self < slice.len()); |
256 | get_noubcheck(slice, self) |
257 | } |
258 | } |
259 | |
260 | #[inline ] |
261 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { |
262 | assert_unsafe_precondition!( |
263 | check_library_ub, |
264 | "slice::get_unchecked_mut requires that the index is within the slice" , |
265 | (this: usize = self, len: usize = slice.len()) => this < len |
266 | ); |
267 | // SAFETY: see comments for `get_unchecked` above. |
268 | unsafe { get_mut_noubcheck(slice, self) } |
269 | } |
270 | |
271 | #[inline ] |
272 | fn index(self, slice: &[T]) -> &T { |
273 | // N.B., use intrinsic indexing |
274 | &(*slice)[self] |
275 | } |
276 | |
277 | #[inline ] |
278 | fn index_mut(self, slice: &mut [T]) -> &mut T { |
279 | // N.B., use intrinsic indexing |
280 | &mut (*slice)[self] |
281 | } |
282 | } |
283 | |
284 | /// Because `IndexRange` guarantees `start <= end`, fewer checks are needed here |
285 | /// than there are for a general `Range<usize>` (which might be `100..3`). |
286 | unsafe impl<T> SliceIndex<[T]> for ops::IndexRange { |
287 | type Output = [T]; |
288 | |
289 | #[inline ] |
290 | fn get(self, slice: &[T]) -> Option<&[T]> { |
291 | if self.end() <= slice.len() { |
292 | // SAFETY: `self` is checked to be valid and in bounds above. |
293 | unsafe { Some(&*get_offset_len_noubcheck(slice, self.start(), self.len())) } |
294 | } else { |
295 | None |
296 | } |
297 | } |
298 | |
299 | #[inline ] |
300 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { |
301 | if self.end() <= slice.len() { |
302 | // SAFETY: `self` is checked to be valid and in bounds above. |
303 | unsafe { Some(&mut *get_offset_len_mut_noubcheck(slice, self.start(), self.len())) } |
304 | } else { |
305 | None |
306 | } |
307 | } |
308 | |
309 | #[inline ] |
310 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { |
311 | assert_unsafe_precondition!( |
312 | check_library_ub, |
313 | "slice::get_unchecked requires that the index is within the slice" , |
314 | (end: usize = self.end(), len: usize = slice.len()) => end <= len |
315 | ); |
316 | // SAFETY: the caller guarantees that `slice` is not dangling, so it |
317 | // cannot be longer than `isize::MAX`. They also guarantee that |
318 | // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, |
319 | // so the call to `add` is safe. |
320 | unsafe { get_offset_len_noubcheck(slice, self.start(), self.len()) } |
321 | } |
322 | |
323 | #[inline ] |
324 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { |
325 | assert_unsafe_precondition!( |
326 | check_library_ub, |
327 | "slice::get_unchecked_mut requires that the index is within the slice" , |
328 | (end: usize = self.end(), len: usize = slice.len()) => end <= len |
329 | ); |
330 | |
331 | // SAFETY: see comments for `get_unchecked` above. |
332 | unsafe { get_offset_len_mut_noubcheck(slice, self.start(), self.len()) } |
333 | } |
334 | |
335 | #[inline ] |
336 | fn index(self, slice: &[T]) -> &[T] { |
337 | if self.end() <= slice.len() { |
338 | // SAFETY: `self` is checked to be valid and in bounds above. |
339 | unsafe { &*get_offset_len_noubcheck(slice, self.start(), self.len()) } |
340 | } else { |
341 | slice_end_index_len_fail(self.end(), slice.len()) |
342 | } |
343 | } |
344 | |
345 | #[inline ] |
346 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { |
347 | if self.end() <= slice.len() { |
348 | // SAFETY: `self` is checked to be valid and in bounds above. |
349 | unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start(), self.len()) } |
350 | } else { |
351 | slice_end_index_len_fail(self.end(), slice.len()) |
352 | } |
353 | } |
354 | } |
355 | |
356 | /// The methods `index` and `index_mut` panic if: |
357 | /// - the start of the range is greater than the end of the range or |
358 | /// - the end of the range is out of bounds. |
359 | #[stable (feature = "slice_get_slice_impls" , since = "1.15.0" )] |
360 | unsafe impl<T> SliceIndex<[T]> for ops::Range<usize> { |
361 | type Output = [T]; |
362 | |
363 | #[inline ] |
364 | fn get(self, slice: &[T]) -> Option<&[T]> { |
365 | // Using checked_sub is a safe way to get `SubUnchecked` in MIR |
366 | if let Some(new_len) = usize::checked_sub(self.end, self.start) |
367 | && self.end <= slice.len() |
368 | { |
369 | // SAFETY: `self` is checked to be valid and in bounds above. |
370 | unsafe { Some(&*get_offset_len_noubcheck(slice, self.start, new_len)) } |
371 | } else { |
372 | None |
373 | } |
374 | } |
375 | |
376 | #[inline ] |
377 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { |
378 | if let Some(new_len) = usize::checked_sub(self.end, self.start) |
379 | && self.end <= slice.len() |
380 | { |
381 | // SAFETY: `self` is checked to be valid and in bounds above. |
382 | unsafe { Some(&mut *get_offset_len_mut_noubcheck(slice, self.start, new_len)) } |
383 | } else { |
384 | None |
385 | } |
386 | } |
387 | |
388 | #[inline ] |
389 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { |
390 | assert_unsafe_precondition!( |
391 | check_library_ub, |
392 | "slice::get_unchecked requires that the range is within the slice" , |
393 | ( |
394 | start: usize = self.start, |
395 | end: usize = self.end, |
396 | len: usize = slice.len() |
397 | ) => end >= start && end <= len |
398 | ); |
399 | |
400 | // SAFETY: the caller guarantees that `slice` is not dangling, so it |
401 | // cannot be longer than `isize::MAX`. They also guarantee that |
402 | // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, |
403 | // so the call to `add` is safe and the length calculation cannot overflow. |
404 | unsafe { |
405 | // Using the intrinsic avoids a superfluous UB check, |
406 | // since the one on this method already checked `end >= start`. |
407 | let new_len = crate::intrinsics::unchecked_sub(self.end, self.start); |
408 | get_offset_len_noubcheck(slice, self.start, new_len) |
409 | } |
410 | } |
411 | |
412 | #[inline ] |
413 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { |
414 | assert_unsafe_precondition!( |
415 | check_library_ub, |
416 | "slice::get_unchecked_mut requires that the range is within the slice" , |
417 | ( |
418 | start: usize = self.start, |
419 | end: usize = self.end, |
420 | len: usize = slice.len() |
421 | ) => end >= start && end <= len |
422 | ); |
423 | // SAFETY: see comments for `get_unchecked` above. |
424 | unsafe { |
425 | let new_len = crate::intrinsics::unchecked_sub(self.end, self.start); |
426 | get_offset_len_mut_noubcheck(slice, self.start, new_len) |
427 | } |
428 | } |
429 | |
430 | #[inline (always)] |
431 | fn index(self, slice: &[T]) -> &[T] { |
432 | // Using checked_sub is a safe way to get `SubUnchecked` in MIR |
433 | let Some(new_len) = usize::checked_sub(self.end, self.start) else { |
434 | slice_index_order_fail(self.start, self.end) |
435 | }; |
436 | if self.end > slice.len() { |
437 | slice_end_index_len_fail(self.end, slice.len()); |
438 | } |
439 | // SAFETY: `self` is checked to be valid and in bounds above. |
440 | unsafe { &*get_offset_len_noubcheck(slice, self.start, new_len) } |
441 | } |
442 | |
443 | #[inline ] |
444 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { |
445 | let Some(new_len) = usize::checked_sub(self.end, self.start) else { |
446 | slice_index_order_fail(self.start, self.end) |
447 | }; |
448 | if self.end > slice.len() { |
449 | slice_end_index_len_fail(self.end, slice.len()); |
450 | } |
451 | // SAFETY: `self` is checked to be valid and in bounds above. |
452 | unsafe { &mut *get_offset_len_mut_noubcheck(slice, self.start, new_len) } |
453 | } |
454 | } |
455 | |
456 | #[unstable (feature = "new_range_api" , issue = "125687" )] |
457 | unsafe impl<T> SliceIndex<[T]> for range::Range<usize> { |
458 | type Output = [T]; |
459 | |
460 | #[inline ] |
461 | fn get(self, slice: &[T]) -> Option<&[T]> { |
462 | ops::Range::from(self).get(slice) |
463 | } |
464 | |
465 | #[inline ] |
466 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { |
467 | ops::Range::from(self).get_mut(slice) |
468 | } |
469 | |
470 | #[inline ] |
471 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { |
472 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. |
473 | unsafe { ops::Range::from(self).get_unchecked(slice) } |
474 | } |
475 | |
476 | #[inline ] |
477 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { |
478 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. |
479 | unsafe { ops::Range::from(self).get_unchecked_mut(slice) } |
480 | } |
481 | |
482 | #[inline (always)] |
483 | fn index(self, slice: &[T]) -> &[T] { |
484 | ops::Range::from(self).index(slice) |
485 | } |
486 | |
487 | #[inline ] |
488 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { |
489 | ops::Range::from(self).index_mut(slice) |
490 | } |
491 | } |
492 | |
493 | /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. |
494 | #[stable (feature = "slice_get_slice_impls" , since = "1.15.0" )] |
495 | unsafe impl<T> SliceIndex<[T]> for ops::RangeTo<usize> { |
496 | type Output = [T]; |
497 | |
498 | #[inline ] |
499 | fn get(self, slice: &[T]) -> Option<&[T]> { |
500 | (0..self.end).get(slice) |
501 | } |
502 | |
503 | #[inline ] |
504 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { |
505 | (0..self.end).get_mut(slice) |
506 | } |
507 | |
508 | #[inline ] |
509 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { |
510 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. |
511 | unsafe { (0..self.end).get_unchecked(slice) } |
512 | } |
513 | |
514 | #[inline ] |
515 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { |
516 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. |
517 | unsafe { (0..self.end).get_unchecked_mut(slice) } |
518 | } |
519 | |
520 | #[inline (always)] |
521 | fn index(self, slice: &[T]) -> &[T] { |
522 | (0..self.end).index(slice) |
523 | } |
524 | |
525 | #[inline ] |
526 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { |
527 | (0..self.end).index_mut(slice) |
528 | } |
529 | } |
530 | |
531 | /// The methods `index` and `index_mut` panic if the start of the range is out of bounds. |
532 | #[stable (feature = "slice_get_slice_impls" , since = "1.15.0" )] |
533 | unsafe impl<T> SliceIndex<[T]> for ops::RangeFrom<usize> { |
534 | type Output = [T]; |
535 | |
536 | #[inline ] |
537 | fn get(self, slice: &[T]) -> Option<&[T]> { |
538 | (self.start..slice.len()).get(slice) |
539 | } |
540 | |
541 | #[inline ] |
542 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { |
543 | (self.start..slice.len()).get_mut(slice) |
544 | } |
545 | |
546 | #[inline ] |
547 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { |
548 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. |
549 | unsafe { (self.start..slice.len()).get_unchecked(slice) } |
550 | } |
551 | |
552 | #[inline ] |
553 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { |
554 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. |
555 | unsafe { (self.start..slice.len()).get_unchecked_mut(slice) } |
556 | } |
557 | |
558 | #[inline ] |
559 | fn index(self, slice: &[T]) -> &[T] { |
560 | if self.start > slice.len() { |
561 | slice_start_index_len_fail(self.start, slice.len()); |
562 | } |
563 | // SAFETY: `self` is checked to be valid and in bounds above. |
564 | unsafe { &*self.get_unchecked(slice) } |
565 | } |
566 | |
567 | #[inline ] |
568 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { |
569 | if self.start > slice.len() { |
570 | slice_start_index_len_fail(self.start, slice.len()); |
571 | } |
572 | // SAFETY: `self` is checked to be valid and in bounds above. |
573 | unsafe { &mut *self.get_unchecked_mut(slice) } |
574 | } |
575 | } |
576 | |
577 | #[unstable (feature = "new_range_api" , issue = "125687" )] |
578 | unsafe impl<T> SliceIndex<[T]> for range::RangeFrom<usize> { |
579 | type Output = [T]; |
580 | |
581 | #[inline ] |
582 | fn get(self, slice: &[T]) -> Option<&[T]> { |
583 | ops::RangeFrom::from(self).get(slice) |
584 | } |
585 | |
586 | #[inline ] |
587 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { |
588 | ops::RangeFrom::from(self).get_mut(slice) |
589 | } |
590 | |
591 | #[inline ] |
592 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { |
593 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. |
594 | unsafe { ops::RangeFrom::from(self).get_unchecked(slice) } |
595 | } |
596 | |
597 | #[inline ] |
598 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { |
599 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. |
600 | unsafe { ops::RangeFrom::from(self).get_unchecked_mut(slice) } |
601 | } |
602 | |
603 | #[inline ] |
604 | fn index(self, slice: &[T]) -> &[T] { |
605 | ops::RangeFrom::from(self).index(slice) |
606 | } |
607 | |
608 | #[inline ] |
609 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { |
610 | ops::RangeFrom::from(self).index_mut(slice) |
611 | } |
612 | } |
613 | |
614 | #[stable (feature = "slice_get_slice_impls" , since = "1.15.0" )] |
615 | unsafe impl<T> SliceIndex<[T]> for ops::RangeFull { |
616 | type Output = [T]; |
617 | |
618 | #[inline ] |
619 | fn get(self, slice: &[T]) -> Option<&[T]> { |
620 | Some(slice) |
621 | } |
622 | |
623 | #[inline ] |
624 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { |
625 | Some(slice) |
626 | } |
627 | |
628 | #[inline ] |
629 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { |
630 | slice |
631 | } |
632 | |
633 | #[inline ] |
634 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { |
635 | slice |
636 | } |
637 | |
638 | #[inline ] |
639 | fn index(self, slice: &[T]) -> &[T] { |
640 | slice |
641 | } |
642 | |
643 | #[inline ] |
644 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { |
645 | slice |
646 | } |
647 | } |
648 | |
649 | /// The methods `index` and `index_mut` panic if: |
650 | /// - the end of the range is `usize::MAX` or |
651 | /// - the start of the range is greater than the end of the range or |
652 | /// - the end of the range is out of bounds. |
653 | #[stable (feature = "inclusive_range" , since = "1.26.0" )] |
654 | unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> { |
655 | type Output = [T]; |
656 | |
657 | #[inline ] |
658 | fn get(self, slice: &[T]) -> Option<&[T]> { |
659 | if *self.end() == usize::MAX { None } else { self.into_slice_range().get(slice) } |
660 | } |
661 | |
662 | #[inline ] |
663 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { |
664 | if *self.end() == usize::MAX { None } else { self.into_slice_range().get_mut(slice) } |
665 | } |
666 | |
667 | #[inline ] |
668 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { |
669 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. |
670 | unsafe { self.into_slice_range().get_unchecked(slice) } |
671 | } |
672 | |
673 | #[inline ] |
674 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { |
675 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. |
676 | unsafe { self.into_slice_range().get_unchecked_mut(slice) } |
677 | } |
678 | |
679 | #[inline ] |
680 | fn index(self, slice: &[T]) -> &[T] { |
681 | if *self.end() == usize::MAX { |
682 | slice_end_index_overflow_fail(); |
683 | } |
684 | self.into_slice_range().index(slice) |
685 | } |
686 | |
687 | #[inline ] |
688 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { |
689 | if *self.end() == usize::MAX { |
690 | slice_end_index_overflow_fail(); |
691 | } |
692 | self.into_slice_range().index_mut(slice) |
693 | } |
694 | } |
695 | |
696 | #[unstable (feature = "new_range_api" , issue = "125687" )] |
697 | unsafe impl<T> SliceIndex<[T]> for range::RangeInclusive<usize> { |
698 | type Output = [T]; |
699 | |
700 | #[inline ] |
701 | fn get(self, slice: &[T]) -> Option<&[T]> { |
702 | ops::RangeInclusive::from(self).get(slice) |
703 | } |
704 | |
705 | #[inline ] |
706 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { |
707 | ops::RangeInclusive::from(self).get_mut(slice) |
708 | } |
709 | |
710 | #[inline ] |
711 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { |
712 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. |
713 | unsafe { ops::RangeInclusive::from(self).get_unchecked(slice) } |
714 | } |
715 | |
716 | #[inline ] |
717 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { |
718 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. |
719 | unsafe { ops::RangeInclusive::from(self).get_unchecked_mut(slice) } |
720 | } |
721 | |
722 | #[inline ] |
723 | fn index(self, slice: &[T]) -> &[T] { |
724 | ops::RangeInclusive::from(self).index(slice) |
725 | } |
726 | |
727 | #[inline ] |
728 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { |
729 | ops::RangeInclusive::from(self).index_mut(slice) |
730 | } |
731 | } |
732 | |
733 | /// The methods `index` and `index_mut` panic if the end of the range is out of bounds. |
734 | #[stable (feature = "inclusive_range" , since = "1.26.0" )] |
735 | unsafe impl<T> SliceIndex<[T]> for ops::RangeToInclusive<usize> { |
736 | type Output = [T]; |
737 | |
738 | #[inline ] |
739 | fn get(self, slice: &[T]) -> Option<&[T]> { |
740 | (0..=self.end).get(slice) |
741 | } |
742 | |
743 | #[inline ] |
744 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { |
745 | (0..=self.end).get_mut(slice) |
746 | } |
747 | |
748 | #[inline ] |
749 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { |
750 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. |
751 | unsafe { (0..=self.end).get_unchecked(slice) } |
752 | } |
753 | |
754 | #[inline ] |
755 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { |
756 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. |
757 | unsafe { (0..=self.end).get_unchecked_mut(slice) } |
758 | } |
759 | |
760 | #[inline ] |
761 | fn index(self, slice: &[T]) -> &[T] { |
762 | (0..=self.end).index(slice) |
763 | } |
764 | |
765 | #[inline ] |
766 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { |
767 | (0..=self.end).index_mut(slice) |
768 | } |
769 | } |
770 | |
771 | /// Performs bounds checking of a range. |
772 | /// |
773 | /// This method is similar to [`Index::index`] for slices, but it returns a |
774 | /// [`Range`] equivalent to `range`. You can use this method to turn any range |
775 | /// into `start` and `end` values. |
776 | /// |
777 | /// `bounds` is the range of the slice to use for bounds checking. It should |
778 | /// be a [`RangeTo`] range that ends at the length of the slice. |
779 | /// |
780 | /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and |
781 | /// [`slice::get_unchecked_mut`] for slices with the given range. |
782 | /// |
783 | /// [`Range`]: ops::Range |
784 | /// [`RangeTo`]: ops::RangeTo |
785 | /// [`slice::get_unchecked`]: slice::get_unchecked |
786 | /// [`slice::get_unchecked_mut`]: slice::get_unchecked_mut |
787 | /// |
788 | /// # Panics |
789 | /// |
790 | /// Panics if `range` would be out of bounds. |
791 | /// |
792 | /// # Examples |
793 | /// |
794 | /// ``` |
795 | /// #![feature(slice_range)] |
796 | /// |
797 | /// use std::slice; |
798 | /// |
799 | /// let v = [10, 40, 30]; |
800 | /// assert_eq!(1..2, slice::range(1..2, ..v.len())); |
801 | /// assert_eq!(0..2, slice::range(..2, ..v.len())); |
802 | /// assert_eq!(1..3, slice::range(1.., ..v.len())); |
803 | /// ``` |
804 | /// |
805 | /// Panics when [`Index::index`] would panic: |
806 | /// |
807 | /// ```should_panic |
808 | /// #![feature(slice_range)] |
809 | /// |
810 | /// use std::slice; |
811 | /// |
812 | /// let _ = slice::range(2..1, ..3); |
813 | /// ``` |
814 | /// |
815 | /// ```should_panic |
816 | /// #![feature(slice_range)] |
817 | /// |
818 | /// use std::slice; |
819 | /// |
820 | /// let _ = slice::range(1..4, ..3); |
821 | /// ``` |
822 | /// |
823 | /// ```should_panic |
824 | /// #![feature(slice_range)] |
825 | /// |
826 | /// use std::slice; |
827 | /// |
828 | /// let _ = slice::range(1..=usize::MAX, ..3); |
829 | /// ``` |
830 | /// |
831 | /// [`Index::index`]: ops::Index::index |
832 | #[track_caller ] |
833 | #[unstable (feature = "slice_range" , issue = "76393" )] |
834 | #[must_use ] |
835 | pub fn range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize> |
836 | where |
837 | R: ops::RangeBounds<usize>, |
838 | { |
839 | let len = bounds.end; |
840 | |
841 | let start = match range.start_bound() { |
842 | ops::Bound::Included(&start) => start, |
843 | ops::Bound::Excluded(start) => { |
844 | start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) |
845 | } |
846 | ops::Bound::Unbounded => 0, |
847 | }; |
848 | |
849 | let end = match range.end_bound() { |
850 | ops::Bound::Included(end) => { |
851 | end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) |
852 | } |
853 | ops::Bound::Excluded(&end) => end, |
854 | ops::Bound::Unbounded => len, |
855 | }; |
856 | |
857 | if start > end { |
858 | slice_index_order_fail(start, end); |
859 | } |
860 | if end > len { |
861 | slice_end_index_len_fail(end, len); |
862 | } |
863 | |
864 | ops::Range { start, end } |
865 | } |
866 | |
867 | /// Performs bounds checking of a range without panicking. |
868 | /// |
869 | /// This is a version of [`range()`] that returns [`None`] instead of panicking. |
870 | /// |
871 | /// # Examples |
872 | /// |
873 | /// ``` |
874 | /// #![feature(slice_range)] |
875 | /// |
876 | /// use std::slice; |
877 | /// |
878 | /// let v = [10, 40, 30]; |
879 | /// assert_eq!(Some(1..2), slice::try_range(1..2, ..v.len())); |
880 | /// assert_eq!(Some(0..2), slice::try_range(..2, ..v.len())); |
881 | /// assert_eq!(Some(1..3), slice::try_range(1.., ..v.len())); |
882 | /// ``` |
883 | /// |
884 | /// Returns [`None`] when [`Index::index`] would panic: |
885 | /// |
886 | /// ``` |
887 | /// #![feature(slice_range)] |
888 | /// |
889 | /// use std::slice; |
890 | /// |
891 | /// assert_eq!(None, slice::try_range(2..1, ..3)); |
892 | /// assert_eq!(None, slice::try_range(1..4, ..3)); |
893 | /// assert_eq!(None, slice::try_range(1..=usize::MAX, ..3)); |
894 | /// ``` |
895 | /// |
896 | /// [`Index::index`]: ops::Index::index |
897 | #[unstable (feature = "slice_range" , issue = "76393" )] |
898 | #[must_use ] |
899 | pub fn try_range<R>(range: R, bounds: ops::RangeTo<usize>) -> Option<ops::Range<usize>> |
900 | where |
901 | R: ops::RangeBounds<usize>, |
902 | { |
903 | let len: usize = bounds.end; |
904 | |
905 | let start: usize = match range.start_bound() { |
906 | ops::Bound::Included(&start: usize) => start, |
907 | ops::Bound::Excluded(start: &usize) => start.checked_add(1)?, |
908 | ops::Bound::Unbounded => 0, |
909 | }; |
910 | |
911 | let end: usize = match range.end_bound() { |
912 | ops::Bound::Included(end: &usize) => end.checked_add(1)?, |
913 | ops::Bound::Excluded(&end: usize) => end, |
914 | ops::Bound::Unbounded => len, |
915 | }; |
916 | |
917 | if start > end || end > len { None } else { Some(ops::Range { start, end }) } |
918 | } |
919 | |
920 | /// Converts a pair of `ops::Bound`s into `ops::Range` without performing any |
921 | /// bounds checking or (in debug) overflow checking. |
922 | pub(crate) fn into_range_unchecked( |
923 | len: usize, |
924 | (start: Bound, end: Bound): (ops::Bound<usize>, ops::Bound<usize>), |
925 | ) -> ops::Range<usize> { |
926 | use ops::Bound; |
927 | let start: usize = match start { |
928 | Bound::Included(i: usize) => i, |
929 | Bound::Excluded(i: usize) => i + 1, |
930 | Bound::Unbounded => 0, |
931 | }; |
932 | let end: usize = match end { |
933 | Bound::Included(i: usize) => i + 1, |
934 | Bound::Excluded(i: usize) => i, |
935 | Bound::Unbounded => len, |
936 | }; |
937 | start..end |
938 | } |
939 | |
940 | /// Converts pair of `ops::Bound`s into `ops::Range`. |
941 | /// Returns `None` on overflowing indices. |
942 | pub(crate) fn into_range( |
943 | len: usize, |
944 | (start: Bound, end: Bound): (ops::Bound<usize>, ops::Bound<usize>), |
945 | ) -> Option<ops::Range<usize>> { |
946 | use ops::Bound; |
947 | let start: usize = match start { |
948 | Bound::Included(start: usize) => start, |
949 | Bound::Excluded(start: usize) => start.checked_add(1)?, |
950 | Bound::Unbounded => 0, |
951 | }; |
952 | |
953 | let end: usize = match end { |
954 | Bound::Included(end: usize) => end.checked_add(1)?, |
955 | Bound::Excluded(end: usize) => end, |
956 | Bound::Unbounded => len, |
957 | }; |
958 | |
959 | // Don't bother with checking `start < end` and `end <= len` |
960 | // since these checks are handled by `Range` impls |
961 | |
962 | Some(start..end) |
963 | } |
964 | |
965 | /// Converts pair of `ops::Bound`s into `ops::Range`. |
966 | /// Panics on overflowing indices. |
967 | pub(crate) fn into_slice_range( |
968 | len: usize, |
969 | (start: Bound, end: Bound): (ops::Bound<usize>, ops::Bound<usize>), |
970 | ) -> ops::Range<usize> { |
971 | use ops::Bound; |
972 | let start: usize = match start { |
973 | Bound::Included(start: usize) => start, |
974 | Bound::Excluded(start: usize) => { |
975 | start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) |
976 | } |
977 | Bound::Unbounded => 0, |
978 | }; |
979 | |
980 | let end: usize = match end { |
981 | Bound::Included(end: usize) => { |
982 | end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) |
983 | } |
984 | Bound::Excluded(end: usize) => end, |
985 | Bound::Unbounded => len, |
986 | }; |
987 | |
988 | // Don't bother with checking `start < end` and `end <= len` |
989 | // since these checks are handled by `Range` impls |
990 | |
991 | start..end |
992 | } |
993 | |
994 | #[stable (feature = "slice_index_with_ops_bound_pair" , since = "1.53.0" )] |
995 | unsafe impl<T> SliceIndex<[T]> for (ops::Bound<usize>, ops::Bound<usize>) { |
996 | type Output = [T]; |
997 | |
998 | #[inline ] |
999 | fn get(self, slice: &[T]) -> Option<&Self::Output> { |
1000 | into_range(slice.len(), self)?.get(slice) |
1001 | } |
1002 | |
1003 | #[inline ] |
1004 | fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { |
1005 | into_range(slice.len(), self)?.get_mut(slice) |
1006 | } |
1007 | |
1008 | #[inline ] |
1009 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { |
1010 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. |
1011 | unsafe { into_range_unchecked(slice.len(), self).get_unchecked(slice) } |
1012 | } |
1013 | |
1014 | #[inline ] |
1015 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { |
1016 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. |
1017 | unsafe { into_range_unchecked(slice.len(), self).get_unchecked_mut(slice) } |
1018 | } |
1019 | |
1020 | #[inline ] |
1021 | fn index(self, slice: &[T]) -> &Self::Output { |
1022 | into_slice_range(slice.len(), self).index(slice) |
1023 | } |
1024 | |
1025 | #[inline ] |
1026 | fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { |
1027 | into_slice_range(slice.len(), self).index_mut(slice) |
1028 | } |
1029 | } |
1030 | |