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