@@ -681,17 +681,15 @@ where
681
681
{
682
682
let len = bounds. end ;
683
683
684
- let start: ops:: Bound < & usize > = range. start_bound ( ) ;
685
- let start = match start {
684
+ let start = match range. start_bound ( ) {
686
685
ops:: Bound :: Included ( & start) => start,
687
686
ops:: Bound :: Excluded ( start) => {
688
687
start. checked_add ( 1 ) . unwrap_or_else ( || slice_start_index_overflow_fail ( ) )
689
688
}
690
689
ops:: Bound :: Unbounded => 0 ,
691
690
} ;
692
691
693
- let end: ops:: Bound < & usize > = range. end_bound ( ) ;
694
- let end = match end {
692
+ let end = match range. end_bound ( ) {
695
693
ops:: Bound :: Included ( end) => {
696
694
end. checked_add ( 1 ) . unwrap_or_else ( || slice_end_index_overflow_fail ( ) )
697
695
}
@@ -709,6 +707,59 @@ where
709
707
ops:: Range { start, end }
710
708
}
711
709
710
+ /// Performs bounds-checking of a range without panicking.
711
+ ///
712
+ /// This is a version of [`range`] that returns [`None`] instead of panicking.
713
+ ///
714
+ /// # Examples
715
+ ///
716
+ /// ```
717
+ /// #![feature(slice_range)]
718
+ ///
719
+ /// use std::slice;
720
+ ///
721
+ /// let v = [10, 40, 30];
722
+ /// assert_eq!(Some(1..2), slice::try_range(1..2, ..v.len()));
723
+ /// assert_eq!(Some(0..2), slice::try_range(..2, ..v.len()));
724
+ /// assert_eq!(Some(1..3), slice::try_range(1.., ..v.len()));
725
+ /// ```
726
+ ///
727
+ /// Returns [`None`] when [`Index::index`] would panic:
728
+ ///
729
+ /// ```
730
+ /// #![feature(slice_range)]
731
+ ///
732
+ /// use std::slice;
733
+ ///
734
+ /// assert_eq!(None, slice::try_range(2..1, ..3));
735
+ /// assert_eq!(None, slice::try_range(1..4, ..3));
736
+ /// assert_eq!(None, slice::try_range(1..=usize::MAX, ..3));
737
+ /// ```
738
+ ///
739
+ /// [`Index::index`]: ops::Index::index
740
+ #[ unstable( feature = "slice_range" , issue = "76393" ) ]
741
+ #[ must_use]
742
+ pub fn try_range < R > ( range : R , bounds : ops:: RangeTo < usize > ) -> Option < ops:: Range < usize > >
743
+ where
744
+ R : ops:: RangeBounds < usize > ,
745
+ {
746
+ let len = bounds. end ;
747
+
748
+ let start = match range. start_bound ( ) {
749
+ ops:: Bound :: Included ( & start) => start,
750
+ ops:: Bound :: Excluded ( start) => start. checked_add ( 1 ) ?,
751
+ ops:: Bound :: Unbounded => 0 ,
752
+ } ;
753
+
754
+ let end = match range. end_bound ( ) {
755
+ ops:: Bound :: Included ( end) => end. checked_add ( 1 ) ?,
756
+ ops:: Bound :: Excluded ( & end) => end,
757
+ ops:: Bound :: Unbounded => len,
758
+ } ;
759
+
760
+ if start > end || end > len { None } else { Some ( ops:: Range { start, end } ) }
761
+ }
762
+
712
763
/// Convert pair of `ops::Bound`s into `ops::Range` without performing any bounds checking and (in debug) overflow checking
713
764
pub ( crate ) fn into_range_unchecked (
714
765
len : usize ,
0 commit comments