diff options
| author | ltdk <usr@ltdk.xyz> | 2024-02-15 10:13:47 -0500 |
|---|---|---|
| committer | ltdk <usr@ltdk.xyz> | 2024-02-15 10:18:33 -0500 |
| commit | 290cbdf50ed7aa856a6794178500c7bd76fc7ec9 (patch) | |
| tree | 80509036ac15179a0ee2400f19ad2e56bd309c51 /library/core/src/slice | |
| parent | fa9f77ff35b4b63ed0cef9a9642c8f881b33f14f (diff) | |
| download | rust-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.rs | 59 | ||||
| -rw-r--r-- | library/core/src/slice/mod.rs | 2 |
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; |
