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