1 | //! Indexing implementations for `[T]`. |
2 | |
3 | use crate::intrinsics::const_eval_select; |
4 | use crate::intrinsics::unchecked_sub; |
5 | use crate::ops; |
6 | use crate::ptr; |
7 | use crate::ub_checks::assert_unsafe_precondition; |
8 | |
9 | #[stable (feature = "rust1" , since = "1.0.0" )] |
10 | impl<T, I> ops::Index<I> for [T] |
11 | where |
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" )] |
23 | impl<T, I> ops::IndexMut<I> for [T] |
24 | where |
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" )] |
37 | const 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 ] |
44 | fn 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 ] |
50 | const 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" )] |
58 | const 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 ] |
65 | fn 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 ] |
71 | const 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" )] |
79 | const 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 ] |
86 | fn 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 ] |
92 | const 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 ] |
99 | const 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 ] |
106 | const fn slice_end_index_overflow_fail() -> ! { |
107 | panic!("attempted to index slice up to maximum usize" ); |
108 | } |
109 | |
110 | mod 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 | )] |
152 | pub 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" )] |
201 | unsafe 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" )] |
262 | unsafe 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" )] |
337 | unsafe 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" )] |
426 | unsafe 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" )] |
465 | unsafe 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" )] |
511 | unsafe 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" )] |
551 | unsafe 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" )] |
596 | unsafe 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 ] |
696 | pub fn range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize> |
697 | where |
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 ] |
760 | pub fn try_range<R>(range: R, bounds: ops::RangeTo<usize>) -> Option<ops::Range<usize>> |
761 | where |
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 |
782 | pub(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. |
802 | pub(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. |
827 | pub(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" )] |
855 | unsafe 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 | |