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