@@ -704,17 +704,15 @@ where
704704{
705705 let len = bounds. end ;
706706
707- let start: ops:: Bound < & usize > = range. start_bound ( ) ;
708- let start = match start {
707+ let start = match range. start_bound ( ) {
709708 ops:: Bound :: Included ( & start) => start,
710709 ops:: Bound :: Excluded ( start) => {
711710 start. checked_add ( 1 ) . unwrap_or_else ( || slice_start_index_overflow_fail ( ) )
712711 }
713712 ops:: Bound :: Unbounded => 0 ,
714713 } ;
715714
716- let end: ops:: Bound < & usize > = range. end_bound ( ) ;
717- let end = match end {
715+ let end = match range. end_bound ( ) {
718716 ops:: Bound :: Included ( end) => {
719717 end. checked_add ( 1 ) . unwrap_or_else ( || slice_end_index_overflow_fail ( ) )
720718 }
@@ -732,6 +730,59 @@ where
732730 ops:: Range { start, end }
733731}
734732
733+ /// Performs bounds-checking of a range without panicking.
734+ ///
735+ /// This is a version of [`range`] that returns [`None`] instead of panicking.
736+ ///
737+ /// # Examples
738+ ///
739+ /// ```
740+ /// #![feature(slice_range)]
741+ ///
742+ /// use std::slice;
743+ ///
744+ /// let v = [10, 40, 30];
745+ /// assert_eq!(Some(1..2), slice::try_range(1..2, ..v.len()));
746+ /// assert_eq!(Some(0..2), slice::try_range(..2, ..v.len()));
747+ /// assert_eq!(Some(1..3), slice::try_range(1.., ..v.len()));
748+ /// ```
749+ ///
750+ /// Returns [`None`] when [`Index::index`] would panic:
751+ ///
752+ /// ```
753+ /// #![feature(slice_range)]
754+ ///
755+ /// use std::slice;
756+ ///
757+ /// assert_eq!(None, slice::try_range(2..1, ..3));
758+ /// assert_eq!(None, slice::try_range(1..4, ..3));
759+ /// assert_eq!(None, slice::try_range(1..=usize::MAX, ..3));
760+ /// ```
761+ ///
762+ /// [`Index::index`]: ops::Index::index
763+ #[ unstable( feature = "slice_range" , issue = "76393" ) ]
764+ #[ must_use]
765+ pub fn try_range < R > ( range : R , bounds : ops:: RangeTo < usize > ) -> Option < ops:: Range < usize > >
766+ where
767+ R : ops:: RangeBounds < usize > ,
768+ {
769+ let len = bounds. end ;
770+
771+ let start = match range. start_bound ( ) {
772+ ops:: Bound :: Included ( & start) => start,
773+ ops:: Bound :: Excluded ( start) => start. checked_add ( 1 ) ?,
774+ ops:: Bound :: Unbounded => 0 ,
775+ } ;
776+
777+ let end = match range. end_bound ( ) {
778+ ops:: Bound :: Included ( end) => end. checked_add ( 1 ) ?,
779+ ops:: Bound :: Excluded ( & end) => end,
780+ ops:: Bound :: Unbounded => len,
781+ } ;
782+
783+ if start > end || end > len { None } else { Some ( ops:: Range { start, end } ) }
784+ }
785+
735786/// Convert pair of `ops::Bound`s into `ops::Range` without performing any bounds checking and (in debug) overflow checking
736787pub ( crate ) fn into_range_unchecked (
737788 len : usize ,
0 commit comments