]>
Commit | Line | Data |
---|---|---|
1b1a35ee XL |
1 | //! Indexing implementations for `[T]`. |
2 | ||
5e7ed085 FG |
3 | use crate::intrinsics::assert_unsafe_precondition; |
4 | use crate::intrinsics::const_eval_select; | |
29967ef6 | 5 | use crate::ops; |
1b1a35ee XL |
6 | use crate::ptr; |
7 | ||
8 | #[stable(feature = "rust1", since = "1.0.0")] | |
5e7ed085 FG |
9 | #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] |
10 | impl<T, I> const ops::Index<I> for [T] | |
1b1a35ee | 11 | where |
5e7ed085 | 12 | I: ~const SliceIndex<[T]>, |
1b1a35ee XL |
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")] | |
5e7ed085 FG |
23 | #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] |
24 | impl<T, I> const ops::IndexMut<I> for [T] | |
1b1a35ee | 25 | where |
5e7ed085 | 26 | I: ~const SliceIndex<[T]>, |
1b1a35ee XL |
27 | { |
28 | #[inline] | |
29 | fn index_mut(&mut self, index: I) -> &mut I::Output { | |
30 | index.index_mut(self) | |
31 | } | |
32 | } | |
33 | ||
a2a8927a XL |
34 | #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] |
35 | #[cfg_attr(feature = "panic_immediate_abort", inline)] | |
1b1a35ee XL |
36 | #[cold] |
37 | #[track_caller] | |
5e7ed085 FG |
38 | #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] |
39 | const fn slice_start_index_len_fail(index: usize, len: usize) -> ! { | |
40 | // SAFETY: we are just panicking here | |
41 | unsafe { | |
42 | const_eval_select( | |
43 | (index, len), | |
44 | slice_start_index_len_fail_ct, | |
45 | slice_start_index_len_fail_rt, | |
46 | ) | |
47 | } | |
48 | } | |
49 | ||
50 | // FIXME const-hack | |
f2b60f7d | 51 | #[track_caller] |
5e7ed085 FG |
52 | fn slice_start_index_len_fail_rt(index: usize, len: usize) -> ! { |
53 | panic!("range start index {index} out of range for slice of length {len}"); | |
54 | } | |
55 | ||
f2b60f7d | 56 | #[track_caller] |
5e7ed085 FG |
57 | const fn slice_start_index_len_fail_ct(_: usize, _: usize) -> ! { |
58 | panic!("slice start index is out of range for slice"); | |
1b1a35ee XL |
59 | } |
60 | ||
a2a8927a XL |
61 | #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] |
62 | #[cfg_attr(feature = "panic_immediate_abort", inline)] | |
1b1a35ee XL |
63 | #[cold] |
64 | #[track_caller] | |
5e7ed085 FG |
65 | #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] |
66 | const fn slice_end_index_len_fail(index: usize, len: usize) -> ! { | |
67 | // SAFETY: we are just panicking here | |
68 | unsafe { | |
69 | const_eval_select((index, len), slice_end_index_len_fail_ct, slice_end_index_len_fail_rt) | |
70 | } | |
71 | } | |
72 | ||
73 | // FIXME const-hack | |
f2b60f7d | 74 | #[track_caller] |
5e7ed085 FG |
75 | fn 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 | ||
f2b60f7d | 79 | #[track_caller] |
5e7ed085 FG |
80 | const fn slice_end_index_len_fail_ct(_: usize, _: usize) -> ! { |
81 | panic!("slice end index is out of range for slice"); | |
1b1a35ee XL |
82 | } |
83 | ||
a2a8927a XL |
84 | #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] |
85 | #[cfg_attr(feature = "panic_immediate_abort", inline)] | |
1b1a35ee XL |
86 | #[cold] |
87 | #[track_caller] | |
5e7ed085 FG |
88 | #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] |
89 | const fn slice_index_order_fail(index: usize, end: usize) -> ! { | |
90 | // SAFETY: we are just panicking here | |
91 | unsafe { const_eval_select((index, end), slice_index_order_fail_ct, slice_index_order_fail_rt) } | |
92 | } | |
93 | ||
94 | // FIXME const-hack | |
f2b60f7d | 95 | #[track_caller] |
5e7ed085 FG |
96 | fn slice_index_order_fail_rt(index: usize, end: usize) -> ! { |
97 | panic!("slice index starts at {index} but ends at {end}"); | |
98 | } | |
99 | ||
f2b60f7d | 100 | #[track_caller] |
5e7ed085 FG |
101 | const fn slice_index_order_fail_ct(_: usize, _: usize) -> ! { |
102 | panic!("slice index start is larger than end"); | |
1b1a35ee XL |
103 | } |
104 | ||
a2a8927a XL |
105 | #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] |
106 | #[cfg_attr(feature = "panic_immediate_abort", inline)] | |
1b1a35ee XL |
107 | #[cold] |
108 | #[track_caller] | |
5e7ed085 | 109 | const fn slice_start_index_overflow_fail() -> ! { |
1b1a35ee XL |
110 | panic!("attempted to index slice from after maximum usize"); |
111 | } | |
112 | ||
a2a8927a XL |
113 | #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] |
114 | #[cfg_attr(feature = "panic_immediate_abort", inline)] | |
1b1a35ee XL |
115 | #[cold] |
116 | #[track_caller] | |
5e7ed085 | 117 | const fn slice_end_index_overflow_fail() -> ! { |
1b1a35ee XL |
118 | panic!("attempted to index slice up to maximum usize"); |
119 | } | |
120 | ||
1b1a35ee XL |
121 | mod 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> {} | |
cdc7bbd5 XL |
140 | #[stable(feature = "slice_index_with_ops_bound_pair", since = "1.53.0")] |
141 | impl Sealed for (ops::Bound<usize>, ops::Bound<usize>) {} | |
1b1a35ee XL |
142 | } |
143 | ||
144 | /// A helper trait used for indexing operations. | |
145 | /// | |
146 | /// Implementations of this trait have to promise that if the argument | |
923072b8 | 147 | /// to `get_unchecked(_mut)` is a safe reference, then so is the result. |
1b1a35ee | 148 | #[stable(feature = "slice_get_slice", since = "1.28.0")] |
04454e1e | 149 | #[rustc_diagnostic_item = "SliceIndex"] |
1b1a35ee XL |
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 = "std::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 shared reference 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 reference 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(self, slice: *const T) -> *const Self::Output; | |
184 | ||
185 | /// Returns a mutable reference to the output at this location, without | |
186 | /// performing any bounds checking. | |
187 | /// Calling this method with an out-of-bounds index or a dangling `slice` pointer | |
188 | /// is *[undefined behavior]* even if the resulting reference is not used. | |
189 | /// | |
190 | /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html | |
191 | #[unstable(feature = "slice_index_methods", issue = "none")] | |
192 | unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output; | |
193 | ||
194 | /// Returns a shared reference to the output at this location, panicking | |
195 | /// if out of bounds. | |
196 | #[unstable(feature = "slice_index_methods", issue = "none")] | |
197 | #[track_caller] | |
198 | fn index(self, slice: &T) -> &Self::Output; | |
199 | ||
200 | /// Returns a mutable reference to the output at this location, panicking | |
201 | /// if out of bounds. | |
202 | #[unstable(feature = "slice_index_methods", issue = "none")] | |
203 | #[track_caller] | |
204 | fn index_mut(self, slice: &mut T) -> &mut Self::Output; | |
205 | } | |
206 | ||
207 | #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] | |
5e7ed085 FG |
208 | #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] |
209 | unsafe impl<T> const SliceIndex<[T]> for usize { | |
1b1a35ee XL |
210 | type Output = T; |
211 | ||
212 | #[inline] | |
213 | fn get(self, slice: &[T]) -> Option<&T> { | |
214 | // SAFETY: `self` is checked to be in bounds. | |
215 | if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None } | |
216 | } | |
217 | ||
218 | #[inline] | |
219 | fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { | |
220 | // SAFETY: `self` is checked to be in bounds. | |
221 | if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None } | |
222 | } | |
223 | ||
224 | #[inline] | |
225 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { | |
f2b60f7d | 226 | let this = self; |
1b1a35ee XL |
227 | // SAFETY: the caller guarantees that `slice` is not dangling, so it |
228 | // cannot be longer than `isize::MAX`. They also guarantee that | |
229 | // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, | |
230 | // so the call to `add` is safe. | |
5e7ed085 | 231 | unsafe { |
f2b60f7d | 232 | assert_unsafe_precondition!([T](this: usize, slice: *const [T]) => this < slice.len()); |
5e7ed085 FG |
233 | slice.as_ptr().add(self) |
234 | } | |
1b1a35ee XL |
235 | } |
236 | ||
237 | #[inline] | |
238 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { | |
f2b60f7d | 239 | let this = self; |
1b1a35ee | 240 | // SAFETY: see comments for `get_unchecked` above. |
5e7ed085 | 241 | unsafe { |
f2b60f7d | 242 | assert_unsafe_precondition!([T](this: usize, slice: *mut [T]) => this < slice.len()); |
5e7ed085 FG |
243 | slice.as_mut_ptr().add(self) |
244 | } | |
1b1a35ee XL |
245 | } |
246 | ||
247 | #[inline] | |
248 | fn index(self, slice: &[T]) -> &T { | |
249 | // N.B., use intrinsic indexing | |
250 | &(*slice)[self] | |
251 | } | |
252 | ||
253 | #[inline] | |
254 | fn index_mut(self, slice: &mut [T]) -> &mut T { | |
255 | // N.B., use intrinsic indexing | |
256 | &mut (*slice)[self] | |
257 | } | |
258 | } | |
259 | ||
260 | #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] | |
5e7ed085 FG |
261 | #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] |
262 | unsafe impl<T> const SliceIndex<[T]> for ops::Range<usize> { | |
1b1a35ee XL |
263 | type Output = [T]; |
264 | ||
265 | #[inline] | |
266 | fn get(self, slice: &[T]) -> Option<&[T]> { | |
267 | if self.start > self.end || self.end > slice.len() { | |
268 | None | |
269 | } else { | |
270 | // SAFETY: `self` is checked to be valid and in bounds above. | |
271 | unsafe { Some(&*self.get_unchecked(slice)) } | |
272 | } | |
273 | } | |
274 | ||
275 | #[inline] | |
276 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { | |
277 | if self.start > self.end || self.end > slice.len() { | |
278 | None | |
279 | } else { | |
280 | // SAFETY: `self` is checked to be valid and in bounds above. | |
281 | unsafe { Some(&mut *self.get_unchecked_mut(slice)) } | |
282 | } | |
283 | } | |
284 | ||
285 | #[inline] | |
286 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { | |
f2b60f7d | 287 | let this = ops::Range { start: self.start, end: self.end }; |
1b1a35ee XL |
288 | // SAFETY: the caller guarantees that `slice` is not dangling, so it |
289 | // cannot be longer than `isize::MAX`. They also guarantee that | |
290 | // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, | |
291 | // so the call to `add` is safe. | |
5e7ed085 FG |
292 | |
293 | unsafe { | |
f2b60f7d FG |
294 | assert_unsafe_precondition!([T](this: ops::Range<usize>, slice: *const [T]) => |
295 | this.end >= this.start && this.end <= slice.len()); | |
5e7ed085 FG |
296 | ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) |
297 | } | |
1b1a35ee XL |
298 | } |
299 | ||
300 | #[inline] | |
301 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { | |
f2b60f7d | 302 | let this = ops::Range { start: self.start, end: self.end }; |
1b1a35ee XL |
303 | // SAFETY: see comments for `get_unchecked` above. |
304 | unsafe { | |
f2b60f7d FG |
305 | assert_unsafe_precondition!([T](this: ops::Range<usize>, slice: *mut [T]) => |
306 | this.end >= this.start && this.end <= slice.len()); | |
1b1a35ee XL |
307 | ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) |
308 | } | |
309 | } | |
310 | ||
311 | #[inline] | |
312 | fn index(self, slice: &[T]) -> &[T] { | |
313 | if self.start > self.end { | |
314 | slice_index_order_fail(self.start, self.end); | |
315 | } else if self.end > slice.len() { | |
316 | slice_end_index_len_fail(self.end, slice.len()); | |
317 | } | |
318 | // SAFETY: `self` is checked to be valid and in bounds above. | |
319 | unsafe { &*self.get_unchecked(slice) } | |
320 | } | |
321 | ||
322 | #[inline] | |
323 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { | |
324 | if self.start > self.end { | |
325 | slice_index_order_fail(self.start, self.end); | |
326 | } else if self.end > slice.len() { | |
327 | slice_end_index_len_fail(self.end, slice.len()); | |
328 | } | |
329 | // SAFETY: `self` is checked to be valid and in bounds above. | |
330 | unsafe { &mut *self.get_unchecked_mut(slice) } | |
331 | } | |
332 | } | |
333 | ||
334 | #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] | |
5e7ed085 FG |
335 | #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] |
336 | unsafe impl<T> const SliceIndex<[T]> for ops::RangeTo<usize> { | |
1b1a35ee XL |
337 | type Output = [T]; |
338 | ||
339 | #[inline] | |
340 | fn get(self, slice: &[T]) -> Option<&[T]> { | |
341 | (0..self.end).get(slice) | |
342 | } | |
343 | ||
344 | #[inline] | |
345 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { | |
346 | (0..self.end).get_mut(slice) | |
347 | } | |
348 | ||
349 | #[inline] | |
350 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { | |
351 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. | |
352 | unsafe { (0..self.end).get_unchecked(slice) } | |
353 | } | |
354 | ||
355 | #[inline] | |
356 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { | |
357 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. | |
358 | unsafe { (0..self.end).get_unchecked_mut(slice) } | |
359 | } | |
360 | ||
361 | #[inline] | |
362 | fn index(self, slice: &[T]) -> &[T] { | |
363 | (0..self.end).index(slice) | |
364 | } | |
365 | ||
366 | #[inline] | |
367 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { | |
368 | (0..self.end).index_mut(slice) | |
369 | } | |
370 | } | |
371 | ||
372 | #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] | |
5e7ed085 FG |
373 | #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] |
374 | unsafe impl<T> const SliceIndex<[T]> for ops::RangeFrom<usize> { | |
1b1a35ee XL |
375 | type Output = [T]; |
376 | ||
377 | #[inline] | |
378 | fn get(self, slice: &[T]) -> Option<&[T]> { | |
379 | (self.start..slice.len()).get(slice) | |
380 | } | |
381 | ||
382 | #[inline] | |
383 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { | |
384 | (self.start..slice.len()).get_mut(slice) | |
385 | } | |
386 | ||
387 | #[inline] | |
388 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { | |
389 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. | |
390 | unsafe { (self.start..slice.len()).get_unchecked(slice) } | |
391 | } | |
392 | ||
393 | #[inline] | |
394 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { | |
395 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. | |
396 | unsafe { (self.start..slice.len()).get_unchecked_mut(slice) } | |
397 | } | |
398 | ||
399 | #[inline] | |
400 | fn index(self, slice: &[T]) -> &[T] { | |
401 | if self.start > slice.len() { | |
402 | slice_start_index_len_fail(self.start, slice.len()); | |
403 | } | |
404 | // SAFETY: `self` is checked to be valid and in bounds above. | |
405 | unsafe { &*self.get_unchecked(slice) } | |
406 | } | |
407 | ||
408 | #[inline] | |
409 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { | |
410 | if self.start > slice.len() { | |
411 | slice_start_index_len_fail(self.start, slice.len()); | |
412 | } | |
413 | // SAFETY: `self` is checked to be valid and in bounds above. | |
414 | unsafe { &mut *self.get_unchecked_mut(slice) } | |
415 | } | |
416 | } | |
417 | ||
418 | #[stable(feature = "slice_get_slice_impls", since = "1.15.0")] | |
5e7ed085 FG |
419 | #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] |
420 | unsafe impl<T> const SliceIndex<[T]> for ops::RangeFull { | |
1b1a35ee XL |
421 | type Output = [T]; |
422 | ||
423 | #[inline] | |
424 | fn get(self, slice: &[T]) -> Option<&[T]> { | |
425 | Some(slice) | |
426 | } | |
427 | ||
428 | #[inline] | |
429 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { | |
430 | Some(slice) | |
431 | } | |
432 | ||
433 | #[inline] | |
434 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { | |
435 | slice | |
436 | } | |
437 | ||
438 | #[inline] | |
439 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { | |
440 | slice | |
441 | } | |
442 | ||
443 | #[inline] | |
444 | fn index(self, slice: &[T]) -> &[T] { | |
445 | slice | |
446 | } | |
447 | ||
448 | #[inline] | |
449 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { | |
450 | slice | |
451 | } | |
452 | } | |
453 | ||
454 | #[stable(feature = "inclusive_range", since = "1.26.0")] | |
5e7ed085 FG |
455 | #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] |
456 | unsafe impl<T> const SliceIndex<[T]> for ops::RangeInclusive<usize> { | |
1b1a35ee XL |
457 | type Output = [T]; |
458 | ||
459 | #[inline] | |
460 | fn get(self, slice: &[T]) -> Option<&[T]> { | |
29967ef6 | 461 | if *self.end() == usize::MAX { None } else { self.into_slice_range().get(slice) } |
1b1a35ee XL |
462 | } |
463 | ||
464 | #[inline] | |
465 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { | |
29967ef6 | 466 | if *self.end() == usize::MAX { None } else { self.into_slice_range().get_mut(slice) } |
1b1a35ee XL |
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`. | |
29967ef6 | 472 | unsafe { self.into_slice_range().get_unchecked(slice) } |
1b1a35ee XL |
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`. | |
29967ef6 | 478 | unsafe { self.into_slice_range().get_unchecked_mut(slice) } |
1b1a35ee XL |
479 | } |
480 | ||
481 | #[inline] | |
482 | fn index(self, slice: &[T]) -> &[T] { | |
483 | if *self.end() == usize::MAX { | |
484 | slice_end_index_overflow_fail(); | |
485 | } | |
29967ef6 | 486 | self.into_slice_range().index(slice) |
1b1a35ee XL |
487 | } |
488 | ||
489 | #[inline] | |
490 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { | |
491 | if *self.end() == usize::MAX { | |
492 | slice_end_index_overflow_fail(); | |
493 | } | |
29967ef6 | 494 | self.into_slice_range().index_mut(slice) |
1b1a35ee XL |
495 | } |
496 | } | |
497 | ||
498 | #[stable(feature = "inclusive_range", since = "1.26.0")] | |
5e7ed085 FG |
499 | #[rustc_const_unstable(feature = "const_slice_index", issue = "none")] |
500 | unsafe impl<T> const SliceIndex<[T]> for ops::RangeToInclusive<usize> { | |
1b1a35ee XL |
501 | type Output = [T]; |
502 | ||
503 | #[inline] | |
504 | fn get(self, slice: &[T]) -> Option<&[T]> { | |
505 | (0..=self.end).get(slice) | |
506 | } | |
507 | ||
508 | #[inline] | |
509 | fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { | |
510 | (0..=self.end).get_mut(slice) | |
511 | } | |
512 | ||
513 | #[inline] | |
514 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { | |
515 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. | |
516 | unsafe { (0..=self.end).get_unchecked(slice) } | |
517 | } | |
518 | ||
519 | #[inline] | |
520 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { | |
521 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. | |
522 | unsafe { (0..=self.end).get_unchecked_mut(slice) } | |
523 | } | |
524 | ||
525 | #[inline] | |
526 | fn index(self, slice: &[T]) -> &[T] { | |
527 | (0..=self.end).index(slice) | |
528 | } | |
529 | ||
530 | #[inline] | |
531 | fn index_mut(self, slice: &mut [T]) -> &mut [T] { | |
532 | (0..=self.end).index_mut(slice) | |
533 | } | |
534 | } | |
6a06907d XL |
535 | |
536 | /// Performs bounds-checking of a range. | |
537 | /// | |
538 | /// This method is similar to [`Index::index`] for slices, but it returns a | |
539 | /// [`Range`] equivalent to `range`. You can use this method to turn any range | |
540 | /// into `start` and `end` values. | |
541 | /// | |
542 | /// `bounds` is the range of the slice to use for bounds-checking. It should | |
543 | /// be a [`RangeTo`] range that ends at the length of the slice. | |
544 | /// | |
545 | /// The returned [`Range`] is safe to pass to [`slice::get_unchecked`] and | |
546 | /// [`slice::get_unchecked_mut`] for slices with the given range. | |
547 | /// | |
548 | /// [`Range`]: ops::Range | |
549 | /// [`RangeTo`]: ops::RangeTo | |
550 | /// [`slice::get_unchecked`]: slice::get_unchecked | |
551 | /// [`slice::get_unchecked_mut`]: slice::get_unchecked_mut | |
552 | /// | |
553 | /// # Panics | |
554 | /// | |
555 | /// Panics if `range` would be out of bounds. | |
556 | /// | |
557 | /// # Examples | |
558 | /// | |
559 | /// ``` | |
560 | /// #![feature(slice_range)] | |
561 | /// | |
562 | /// use std::slice; | |
563 | /// | |
564 | /// let v = [10, 40, 30]; | |
565 | /// assert_eq!(1..2, slice::range(1..2, ..v.len())); | |
566 | /// assert_eq!(0..2, slice::range(..2, ..v.len())); | |
567 | /// assert_eq!(1..3, slice::range(1.., ..v.len())); | |
568 | /// ``` | |
569 | /// | |
570 | /// Panics when [`Index::index`] would panic: | |
571 | /// | |
572 | /// ```should_panic | |
573 | /// #![feature(slice_range)] | |
574 | /// | |
575 | /// use std::slice; | |
576 | /// | |
5e7ed085 | 577 | /// let _ = slice::range(2..1, ..3); |
6a06907d XL |
578 | /// ``` |
579 | /// | |
580 | /// ```should_panic | |
581 | /// #![feature(slice_range)] | |
582 | /// | |
583 | /// use std::slice; | |
584 | /// | |
5e7ed085 | 585 | /// let _ = slice::range(1..4, ..3); |
6a06907d XL |
586 | /// ``` |
587 | /// | |
588 | /// ```should_panic | |
589 | /// #![feature(slice_range)] | |
590 | /// | |
591 | /// use std::slice; | |
592 | /// | |
5e7ed085 | 593 | /// let _ = slice::range(1..=usize::MAX, ..3); |
6a06907d XL |
594 | /// ``` |
595 | /// | |
596 | /// [`Index::index`]: ops::Index::index | |
597 | #[track_caller] | |
598 | #[unstable(feature = "slice_range", issue = "76393")] | |
5e7ed085 | 599 | #[must_use] |
6a06907d XL |
600 | pub fn range<R>(range: R, bounds: ops::RangeTo<usize>) -> ops::Range<usize> |
601 | where | |
602 | R: ops::RangeBounds<usize>, | |
603 | { | |
604 | let len = bounds.end; | |
605 | ||
606 | let start: ops::Bound<&usize> = range.start_bound(); | |
607 | let start = match start { | |
608 | ops::Bound::Included(&start) => start, | |
609 | ops::Bound::Excluded(start) => { | |
610 | start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) | |
611 | } | |
612 | ops::Bound::Unbounded => 0, | |
613 | }; | |
614 | ||
615 | let end: ops::Bound<&usize> = range.end_bound(); | |
616 | let end = match end { | |
617 | ops::Bound::Included(end) => { | |
618 | end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) | |
619 | } | |
620 | ops::Bound::Excluded(&end) => end, | |
621 | ops::Bound::Unbounded => len, | |
622 | }; | |
623 | ||
624 | if start > end { | |
625 | slice_index_order_fail(start, end); | |
626 | } | |
627 | if end > len { | |
628 | slice_end_index_len_fail(end, len); | |
629 | } | |
630 | ||
631 | ops::Range { start, end } | |
632 | } | |
cdc7bbd5 XL |
633 | |
634 | /// Convert pair of `ops::Bound`s into `ops::Range` without performing any bounds checking and (in debug) overflow checking | |
635 | fn into_range_unchecked( | |
636 | len: usize, | |
637 | (start, end): (ops::Bound<usize>, ops::Bound<usize>), | |
638 | ) -> ops::Range<usize> { | |
639 | use ops::Bound; | |
640 | let start = match start { | |
641 | Bound::Included(i) => i, | |
642 | Bound::Excluded(i) => i + 1, | |
643 | Bound::Unbounded => 0, | |
644 | }; | |
645 | let end = match end { | |
646 | Bound::Included(i) => i + 1, | |
647 | Bound::Excluded(i) => i, | |
648 | Bound::Unbounded => len, | |
649 | }; | |
650 | start..end | |
651 | } | |
652 | ||
653 | /// Convert pair of `ops::Bound`s into `ops::Range`. | |
654 | /// Returns `None` on overflowing indices. | |
655 | fn into_range( | |
656 | len: usize, | |
657 | (start, end): (ops::Bound<usize>, ops::Bound<usize>), | |
658 | ) -> Option<ops::Range<usize>> { | |
659 | use ops::Bound; | |
660 | let start = match start { | |
661 | Bound::Included(start) => start, | |
662 | Bound::Excluded(start) => start.checked_add(1)?, | |
663 | Bound::Unbounded => 0, | |
664 | }; | |
665 | ||
666 | let end = match end { | |
667 | Bound::Included(end) => end.checked_add(1)?, | |
668 | Bound::Excluded(end) => end, | |
669 | Bound::Unbounded => len, | |
670 | }; | |
671 | ||
672 | // Don't bother with checking `start < end` and `end <= len` | |
673 | // since these checks are handled by `Range` impls | |
674 | ||
675 | Some(start..end) | |
676 | } | |
677 | ||
678 | /// Convert pair of `ops::Bound`s into `ops::Range`. | |
679 | /// Panics on overflowing indices. | |
680 | fn into_slice_range( | |
681 | len: usize, | |
682 | (start, end): (ops::Bound<usize>, ops::Bound<usize>), | |
683 | ) -> ops::Range<usize> { | |
684 | use ops::Bound; | |
685 | let start = match start { | |
686 | Bound::Included(start) => start, | |
687 | Bound::Excluded(start) => { | |
688 | start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) | |
689 | } | |
690 | Bound::Unbounded => 0, | |
691 | }; | |
692 | ||
693 | let end = match end { | |
694 | Bound::Included(end) => { | |
695 | end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) | |
696 | } | |
697 | Bound::Excluded(end) => end, | |
698 | Bound::Unbounded => len, | |
699 | }; | |
700 | ||
701 | // Don't bother with checking `start < end` and `end <= len` | |
702 | // since these checks are handled by `Range` impls | |
703 | ||
704 | start..end | |
705 | } | |
706 | ||
707 | #[stable(feature = "slice_index_with_ops_bound_pair", since = "1.53.0")] | |
708 | unsafe impl<T> SliceIndex<[T]> for (ops::Bound<usize>, ops::Bound<usize>) { | |
709 | type Output = [T]; | |
710 | ||
711 | #[inline] | |
712 | fn get(self, slice: &[T]) -> Option<&Self::Output> { | |
713 | into_range(slice.len(), self)?.get(slice) | |
714 | } | |
715 | ||
716 | #[inline] | |
717 | fn get_mut(self, slice: &mut [T]) -> Option<&mut Self::Output> { | |
718 | into_range(slice.len(), self)?.get_mut(slice) | |
719 | } | |
720 | ||
721 | #[inline] | |
722 | unsafe fn get_unchecked(self, slice: *const [T]) -> *const Self::Output { | |
723 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. | |
724 | unsafe { into_range_unchecked(slice.len(), self).get_unchecked(slice) } | |
725 | } | |
726 | ||
727 | #[inline] | |
728 | unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut Self::Output { | |
729 | // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. | |
730 | unsafe { into_range_unchecked(slice.len(), self).get_unchecked_mut(slice) } | |
731 | } | |
732 | ||
733 | #[inline] | |
734 | fn index(self, slice: &[T]) -> &Self::Output { | |
735 | into_slice_range(slice.len(), self).index(slice) | |
736 | } | |
737 | ||
738 | #[inline] | |
739 | fn index_mut(self, slice: &mut [T]) -> &mut Self::Output { | |
740 | into_slice_range(slice.len(), self).index_mut(slice) | |
741 | } | |
742 | } |