index.rs - source (original) (raw)
core/slice/
index.rs
1//! Indexing implementations for `[T]`.
2
3use crate::panic::const_panic;
4use crate::ub_checks::assert_unsafe_precondition;
5use crate::{ops, range};
6
7#[stable(feature = "rust1", since = "1.0.0")]
8impl<T, I> ops::Index<I> for [T]
9where
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")]
21impl<T, I> ops::IndexMut<I> for [T]
22where
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]
34const 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]
46const 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]
58const 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]
70const 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]
77const 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)]
87const unsafe fn get_noubcheck<T>(ptr: *const [T], index: usize) -> *const T {
88 let ptr = ptr as *const T;
89 // SAFETY: The caller already checked these preconditions
90 unsafe { crate::intrinsics::offset(ptr, index) }
91}
92
93#[inline(always)]
94const unsafe fn get_mut_noubcheck<T>(ptr: *mut [T], index: usize) -> *mut T {
95 let ptr = ptr as *mut T;
96 // SAFETY: The caller already checked these preconditions
97 unsafe { crate::intrinsics::offset(ptr, index) }
98}
99
100#[inline(always)]
101const 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 = unsafe { get_noubcheck(ptr, offset) };
108 crate::intrinsics::aggregate_raw_ptr(ptr, len)
109}
110
111#[inline(always)]
112const 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 = unsafe { get_mut_noubcheck(ptr, offset) };
119 crate::intrinsics::aggregate_raw_ptr(ptr, len)
120}
121
122mod 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"), _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)]
172pub 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")]
222unsafe 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`).
286unsafe 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")]
360unsafe 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")]
457unsafe 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")]
495unsafe 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")]
533unsafe 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")]
578unsafe 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")]
615unsafe 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")]
654unsafe 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")]
697unsafe 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")]
735unsafe 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]
835pub fn range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize>
836where
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]
899pub fn try_range<R>(range: R, bounds: ops::RangeTo<usize>) -> Option<ops::Range<usize>>
900where
901 R: ops::RangeBounds<usize>,
902{
903 let len = bounds.end;
904
905 let start = match range.start_bound() {
906 ops::Bound::Included(&start) => start,
907 ops::Bound::Excluded(start) => start.checked_add(1)?,
908 ops::Bound::Unbounded => 0,
909 };
910
911 let end = match range.end_bound() {
912 ops::Bound::Included(end) => end.checked_add(1)?,
913 ops::Bound::Excluded(&end) => 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.
922pub(crate) fn into_range_unchecked(
923 len: usize,
924 (start, end): (ops::Bound<usize>, ops::Bound<usize>),
925) -> ops::Range<usize> {
926 use ops::Bound;
927 let start = match start {
928 Bound::Included(i) => i,
929 Bound::Excluded(i) => i + 1,
930 Bound::Unbounded => 0,
931 };
932 let end = match end {
933 Bound::Included(i) => i + 1,
934 Bound::Excluded(i) => 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.
942pub(crate) fn into_range(
943 len: usize,
944 (start, end): (ops::Bound<usize>, ops::Bound<usize>),
945) -> Option<ops::Range<usize>> {
946 use ops::Bound;
947 let start = match start {
948 Bound::Included(start) => start,
949 Bound::Excluded(start) => start.checked_add(1)?,
950 Bound::Unbounded => 0,
951 };
952
953 let end = match end {
954 Bound::Included(end) => end.checked_add(1)?,
955 Bound::Excluded(end) => 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.
967pub(crate) fn into_slice_range(
968 len: usize,
969 (start, end): (ops::Bound<usize>, ops::Bound<usize>),
970) -> ops::Range<usize> {
971 use ops::Bound;
972 let start = match start {
973 Bound::Included(start) => start,
974 Bound::Excluded(start) => {
975 start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
976 }
977 Bound::Unbounded => 0,
978 };
979
980 let end = match end {
981 Bound::Included(end) => {
982 end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
983 }
984 Bound::Excluded(end) => 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")]
995unsafe 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}