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