Skip to main content

core/slice/
index.rs

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