@@ -29,7 +29,7 @@ use crate::intrinsics::{assume, exact_div, is_aligned_and_not_null, unchecked_su
2929use crate :: iter:: * ;
3030use crate :: marker:: { self , Copy , Send , Sized , Sync } ;
3131use crate :: mem;
32- use crate :: ops:: { self , FnMut , Range } ;
32+ use crate :: ops:: { self , Bound , FnMut , Range , RangeBounds } ;
3333use crate :: option:: Option ;
3434use crate :: option:: Option :: { None , Some } ;
3535use crate :: ptr:: { self , NonNull } ;
@@ -355,6 +355,79 @@ impl<T> [T] {
355355 unsafe { & mut * index. get_unchecked_mut ( self ) }
356356 }
357357
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+
358431 /// Returns a raw pointer to the slice's buffer.
359432 ///
360433 /// The caller must ensure that the slice outlives the pointer this
@@ -2651,26 +2724,11 @@ impl<T> [T] {
26512724 /// ```
26522725 #[ stable( feature = "copy_within" , since = "1.37.0" ) ]
26532726 #[ 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 )
26552728 where
26562729 T : Copy ,
26572730 {
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) ;
26742732 let count = src_end - src_start;
26752733 assert ! ( dest <= self . len( ) - count, "dest is out of bounds" ) ;
26762734 // SAFETY: the conditions for `ptr::copy` have all been checked above,
@@ -3259,7 +3317,14 @@ fn slice_index_order_fail(index: usize, end: usize) -> ! {
32593317#[ inline( never) ]
32603318#[ cold]
32613319#[ 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 ( ) -> ! {
32633328 panic ! ( "attempted to index slice up to maximum usize" ) ;
32643329}
32653330
@@ -3603,15 +3668,15 @@ unsafe impl<T> SliceIndex<[T]> for ops::RangeInclusive<usize> {
36033668 #[ inline]
36043669 fn index ( self , slice : & [ T ] ) -> & [ T ] {
36053670 if * self . end ( ) == usize:: MAX {
3606- slice_index_overflow_fail ( ) ;
3671+ slice_end_index_overflow_fail ( ) ;
36073672 }
36083673 ( * self . start ( ) ..self . end ( ) + 1 ) . index ( slice)
36093674 }
36103675
36113676 #[ inline]
36123677 fn index_mut ( self , slice : & mut [ T ] ) -> & mut [ T ] {
36133678 if * self . end ( ) == usize:: MAX {
3614- slice_index_overflow_fail ( ) ;
3679+ slice_end_index_overflow_fail ( ) ;
36153680 }
36163681 ( * self . start ( ) ..self . end ( ) + 1 ) . index_mut ( slice)
36173682 }
0 commit comments