about summary refs log tree commit diff
path: root/library/core/src/slice
diff options
context:
space:
mode:
authorltdk <usr@ltdk.xyz>2024-02-15 10:13:47 -0500
committerltdk <usr@ltdk.xyz>2024-02-15 10:18:33 -0500
commit290cbdf50ed7aa856a6794178500c7bd76fc7ec9 (patch)
tree80509036ac15179a0ee2400f19ad2e56bd309c51 /library/core/src/slice
parentfa9f77ff35b4b63ed0cef9a9642c8f881b33f14f (diff)
downloadrust-290cbdf50ed7aa856a6794178500c7bd76fc7ec9.tar.gz
rust-290cbdf50ed7aa856a6794178500c7bd76fc7ec9.zip
Add slice::try_range
Diffstat (limited to 'library/core/src/slice')
-rw-r--r--library/core/src/slice/index.rs59
-rw-r--r--library/core/src/slice/mod.rs2
2 files changed, 56 insertions, 5 deletions
diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs
index fb9be396eab..c34d616e268 100644
--- a/library/core/src/slice/index.rs
+++ b/library/core/src/slice/index.rs
@@ -681,8 +681,7 @@ where
 {
     let len = bounds.end;
 
-    let start: ops::Bound<&usize> = range.start_bound();
-    let start = match start {
+    let start = match range.start_bound() {
         ops::Bound::Included(&start) => start,
         ops::Bound::Excluded(start) => {
             start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail())
@@ -690,8 +689,7 @@ where
         ops::Bound::Unbounded => 0,
     };
 
-    let end: ops::Bound<&usize> = range.end_bound();
-    let end = match end {
+    let end = match range.end_bound() {
         ops::Bound::Included(end) => {
             end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail())
         }
@@ -709,6 +707,59 @@ where
     ops::Range { start, end }
 }
 
+/// Performs bounds-checking of a range without panicking.
+///
+/// This is a version of [`range`] that returns [`None`] instead of panicking.
+///
+/// # Examples
+///
+/// ```
+/// #![feature(slice_range)]
+///
+/// use std::slice;
+///
+/// let v = [10, 40, 30];
+/// assert_eq!(Some(1..2), slice::try_range(1..2, ..v.len()));
+/// assert_eq!(Some(0..2), slice::try_range(..2, ..v.len()));
+/// assert_eq!(Some(1..3), slice::try_range(1.., ..v.len()));
+/// ```
+///
+/// Returns [`None`] when [`Index::index`] would panic:
+///
+/// ```
+/// #![feature(slice_range)]
+///
+/// use std::slice;
+///
+/// assert_eq!(None, slice::try_range(2..1, ..3));
+/// assert_eq!(None, slice::try_range(1..4, ..3));
+/// assert_eq!(None, slice::try_range(1..=usize::MAX, ..3));
+/// ```
+///
+/// [`Index::index`]: ops::Index::index
+#[unstable(feature = "slice_range", issue = "76393")]
+#[must_use]
+pub fn try_range<R>(range: R, bounds: ops::RangeTo<usize>) -> Option<ops::Range<usize>>
+where
+    R: ops::RangeBounds<usize>,
+{
+    let len = bounds.end;
+
+    let start = match range.start_bound() {
+        ops::Bound::Included(&start) => start,
+        ops::Bound::Excluded(start) => start.checked_add(1)?,
+        ops::Bound::Unbounded => 0,
+    };
+
+    let end = match range.end_bound() {
+        ops::Bound::Included(end) => end.checked_add(1)?,
+        ops::Bound::Excluded(&end) => end,
+        ops::Bound::Unbounded => len,
+    };
+
+    if start > end || end > len { None } else { Some(ops::Range { start, end }) }
+}
+
 /// Convert pair of `ops::Bound`s into `ops::Range` without performing any bounds checking and (in debug) overflow checking
 pub(crate) fn into_range_unchecked(
     len: usize,
diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs
index 73e92ed1dad..aa228e12325 100644
--- a/library/core/src/slice/mod.rs
+++ b/library/core/src/slice/mod.rs
@@ -91,7 +91,7 @@ pub use sort::heapsort;
 pub use index::SliceIndex;
 
 #[unstable(feature = "slice_range", issue = "76393")]
-pub use index::range;
+pub use index::{range, try_range};
 
 #[stable(feature = "inherent_ascii_escape", since = "1.60.0")]
 pub use ascii::EscapeAscii;