@@ -29,7 +29,7 @@ use crate::intrinsics::{assume, exact_div, is_aligned_and_not_null, unchecked_su
29
29
use crate :: iter:: * ;
30
30
use crate :: marker:: { self , Copy , Send , Sized , Sync } ;
31
31
use crate :: mem;
32
- use crate :: ops:: { self , FnMut , Range } ;
32
+ use crate :: ops:: { self , Bound , FnMut , Range , RangeBounds } ;
33
33
use crate :: option:: Option ;
34
34
use crate :: option:: Option :: { None , Some } ;
35
35
use crate :: ptr:: { self , NonNull } ;
@@ -355,6 +355,79 @@ impl<T> [T] {
355
355
unsafe { & mut * index. get_unchecked_mut ( self ) }
356
356
}
357
357
358
+ /// Converts a range over this slice to [`Range`].
359
+ ///
360
+ /// The returned range is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`].
361
+ ///
362
+ /// [`get_unchecked`]: #method.get_unchecked
363
+ /// [`get_unchecked_mut`]: #method.get_unchecked_mut
364
+ ///
365
+ /// # Panics
366
+ ///
367
+ /// Panics if the range is out of bounds.
368
+ ///
369
+ /// # Examples
370
+ ///
371
+ /// ```
372
+ /// #![feature(slice_check_range)]
373
+ ///
374
+ /// let v = [10, 40, 30];
375
+ /// assert_eq!(1..2, v.check_range(1..2));
376
+ /// assert_eq!(0..2, v.check_range(..2));
377
+ /// assert_eq!(1..3, v.check_range(1..));
378
+ /// ```
379
+ ///
380
+ /// Panics when [`Index::index`] would panic:
381
+ ///
382
+ /// ```should_panic
383
+ /// #![feature(slice_check_range)]
384
+ ///
385
+ /// [10, 40, 30].check_range(2..1);
386
+ /// ```
387
+ ///
388
+ /// ```should_panic
389
+ /// #![feature(slice_check_range)]
390
+ ///
391
+ /// [10, 40, 30].check_range(1..4);
392
+ /// ```
393
+ ///
394
+ /// ```should_panic
395
+ /// #![feature(slice_check_range)]
396
+ ///
397
+ /// [10, 40, 30].check_range(1..=usize::MAX);
398
+ /// ```
399
+ ///
400
+ /// [`Index::index`]: ops::Index::index
401
+ #[ track_caller]
402
+ #[ unstable( feature = "slice_check_range" , issue = "none" ) ]
403
+ pub fn check_range < R : RangeBounds < usize > > ( & self , range : R ) -> Range < usize > {
404
+ let start = match range. start_bound ( ) {
405
+ Bound :: Included ( & start) => start,
406
+ Bound :: Excluded ( start) => {
407
+ start. checked_add ( 1 ) . unwrap_or_else ( || slice_start_index_overflow_fail ( ) )
408
+ }
409
+ Bound :: Unbounded => 0 ,
410
+ } ;
411
+
412
+ let len = self . len ( ) ;
413
+ let end = match range. end_bound ( ) {
414
+ Bound :: Included ( end) => {
415
+ end. checked_add ( 1 ) . unwrap_or_else ( || slice_end_index_overflow_fail ( ) )
416
+ }
417
+ Bound :: Excluded ( & end) => end,
418
+ Bound :: Unbounded => len,
419
+ } ;
420
+
421
+ if start > end {
422
+ slice_index_order_fail ( start, end) ;
423
+ }
424
+ if end > len {
425
+ slice_end_index_len_fail ( end, len) ;
426
+ }
427
+
428
+ Range { start, end }
429
+ }
430
+
358
431
/// Returns a raw pointer to the slice's buffer.
359
432
///
360
433
/// The caller must ensure that the slice outlives the pointer this
@@ -2651,26 +2724,11 @@ impl<T> [T] {
2651
2724
/// ```
2652
2725
#[ stable( feature = "copy_within" , since = "1.37.0" ) ]
2653
2726
#[ track_caller]
2654
- pub fn copy_within < R : ops :: RangeBounds < usize > > ( & mut self , src : R , dest : usize )
2727
+ pub fn copy_within < R : RangeBounds < usize > > ( & mut self , src : R , dest : usize )
2655
2728
where
2656
2729
T : Copy ,
2657
2730
{
2658
- let src_start = match src. start_bound ( ) {
2659
- ops:: Bound :: Included ( & n) => n,
2660
- ops:: Bound :: Excluded ( & n) => {
2661
- n. checked_add ( 1 ) . unwrap_or_else ( || slice_index_overflow_fail ( ) )
2662
- }
2663
- ops:: Bound :: Unbounded => 0 ,
2664
- } ;
2665
- let src_end = match src. end_bound ( ) {
2666
- ops:: Bound :: Included ( & n) => {
2667
- n. checked_add ( 1 ) . unwrap_or_else ( || slice_index_overflow_fail ( ) )
2668
- }
2669
- ops:: Bound :: Excluded ( & n) => n,
2670
- ops:: Bound :: Unbounded => self . len ( ) ,
2671
- } ;
2672
- assert ! ( src_start <= src_end, "src end is before src start" ) ;
2673
- assert ! ( src_end <= self . len( ) , "src is out of bounds" ) ;
2731
+ let Range { start : src_start, end : src_end } = self . check_range ( src) ;
2674
2732
let count = src_end - src_start;
2675
2733
assert ! ( dest <= self . len( ) - count, "dest is out of bounds" ) ;
2676
2734
// SAFETY: the conditions for `ptr::copy` have all been checked above,
@@ -3259,7 +3317,14 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! {
3259
3317
#[ inline( never) ]
3260
3318
#[ cold]
3261
3319
#[ track_caller]
3262
- fn slice_index_overflow_fail ( ) -> ! {
3320
+ fn slice_start_index_overflow_fail ( ) -> ! {
3321
+ panic ! ( "attempted to index slice from after maximum usize" ) ;
3322
+ }
3323
+
3324
+ #[ inline( never) ]
3325
+ #[ cold]
3326
+ #[ track_caller]
3327
+ fn slice_end_index_overflow_fail ( ) -> ! {
3263
3328
panic ! ( "attempted to index slice up to maximum usize" ) ;
3264
3329
}
3265
3330
@@ -3603,15 +3668,15 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
3603
3668
#[ inline]
3604
3669
fn index ( self , slice : & [ T ] ) -> & [ T ] {
3605
3670
if * self . end ( ) == usize:: MAX {
3606
- slice_index_overflow_fail ( ) ;
3671
+ slice_end_index_overflow_fail ( ) ;
3607
3672
}
3608
3673
( * self . start ( ) ..self . end ( ) + 1 ) . index ( slice)
3609
3674
}
3610
3675
3611
3676
#[ inline]
3612
3677
fn index_mut ( self , slice : & mut [ T ] ) -> & mut [ T ] {
3613
3678
if * self . end ( ) == usize:: MAX {
3614
- slice_index_overflow_fail ( ) ;
3679
+ slice_end_index_overflow_fail ( ) ;
3615
3680
}
3616
3681
( * self . start ( ) ..self . end ( ) + 1 ) . index_mut ( slice)
3617
3682
}
0 commit comments