diff options
| author | Taylor Cramer <cramertj@google.com> | 2025-02-04 11:42:29 -0800 |
|---|---|---|
| committer | Taylor Cramer <cramertj@google.com> | 2025-02-04 11:45:21 -0800 |
| commit | 836a989820aa82a7bb35c9fba670ab733406a84f (patch) | |
| tree | 59c99365dfc7c08fda198cac67abb9ca0bc64bef /library/core | |
| parent | 07cf20e98773677746d09f10ff4bdae8b7ee22c6 (diff) | |
| download | rust-836a989820aa82a7bb35c9fba670ab733406a84f.tar.gz rust-836a989820aa82a7bb35c9fba670ab733406a84f.zip | |
Add OneSidedRangeBound to eliminate panic in `split_point_of`
See discussion in https://github.com/rust-lang/rust/pull/88502/files#r760177240
Diffstat (limited to 'library/core')
| -rw-r--r-- | library/core/src/ops/mod.rs | 4 | ||||
| -rw-r--r-- | library/core/src/ops/range.rs | 46 | ||||
| -rw-r--r-- | library/core/src/slice/mod.rs | 16 |
3 files changed, 51 insertions, 15 deletions
diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index 40526f9583e..7b2ced2cc4b 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -182,10 +182,10 @@ pub use self::function::{Fn, FnMut, FnOnce}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::index::{Index, IndexMut}; pub(crate) use self::index_range::IndexRange; -#[unstable(feature = "one_sided_range", issue = "69780")] -pub use self::range::OneSidedRange; #[stable(feature = "inclusive_range", since = "1.26.0")] pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive}; +#[unstable(feature = "one_sided_range", issue = "69780")] +pub use self::range::{OneSidedRange, OneSidedRangeBound}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::range::{Range, RangeFrom, RangeFull, RangeTo}; #[unstable(feature = "try_trait_v2_residual", issue = "91285")] diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index 727a22e454d..42e07a0e51d 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -979,6 +979,19 @@ impl<T> RangeBounds<T> for RangeToInclusive<&T> { } } +/// An internal helper for `split_off` functions indicating +/// which end a `OneSidedRange` is bounded on. +#[unstable(feature = "one_sided_range", issue = "69780")] +#[allow(missing_debug_implementations)] +pub enum OneSidedRangeBound { + /// The range is bounded inclusively from below and is unbounded above. + StartInclusive, + /// The range is bounded exclusively from above and is unbounded below. + End, + /// The range is bounded inclusively from above and is unbounded below. + EndInclusive, +} + /// `OneSidedRange` is implemented for built-in range types that are unbounded /// on one side. For example, `a..`, `..b` and `..=c` implement `OneSidedRange`, /// but `..`, `d..e`, and `f..=g` do not. @@ -986,13 +999,38 @@ impl<T> RangeBounds<T> for RangeToInclusive<&T> { /// Types that implement `OneSidedRange<T>` must return `Bound::Unbounded` /// from one of `RangeBounds::start_bound` or `RangeBounds::end_bound`. #[unstable(feature = "one_sided_range", issue = "69780")] -pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> {} +pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> { + /// An internal-only helper function for `split_off` and + /// `split_off_mut` that returns the bound of the one-sided range. + fn bound(self) -> (OneSidedRangeBound, T); +} #[unstable(feature = "one_sided_range", issue = "69780")] -impl<T> OneSidedRange<T> for RangeTo<T> where Self: RangeBounds<T> {} +impl<T> OneSidedRange<T> for RangeTo<T> +where + Self: RangeBounds<T>, +{ + fn bound(self) -> (OneSidedRangeBound, T) { + (OneSidedRangeBound::End, self.end) + } +} #[unstable(feature = "one_sided_range", issue = "69780")] -impl<T> OneSidedRange<T> for RangeFrom<T> where Self: RangeBounds<T> {} +impl<T> OneSidedRange<T> for RangeFrom<T> +where + Self: RangeBounds<T>, +{ + fn bound(self) -> (OneSidedRangeBound, T) { + (OneSidedRangeBound::StartInclusive, self.start) + } +} #[unstable(feature = "one_sided_range", issue = "69780")] -impl<T> OneSidedRange<T> for RangeToInclusive<T> where Self: RangeBounds<T> {} +impl<T> OneSidedRange<T> for RangeToInclusive<T> +where + Self: RangeBounds<T>, +{ + fn bound(self) -> (OneSidedRangeBound, T) { + (OneSidedRangeBound::EndInclusive, self.end) + } +} diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index dd2b2fd15f9..fe9d7c10db2 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -10,7 +10,7 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::intrinsics::{exact_div, unchecked_sub}; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZero; -use crate::ops::{Bound, OneSidedRange, Range, RangeBounds, RangeInclusive}; +use crate::ops::{OneSidedRange, OneSidedRangeBound, Range, RangeBounds, RangeInclusive}; use crate::panic::const_panic; use crate::simd::{self, Simd}; use crate::ub_checks::assert_unsafe_precondition; @@ -83,14 +83,12 @@ pub use raw::{from_raw_parts, from_raw_parts_mut}; /// which to split. Returns `None` if the split index would overflow. #[inline] fn split_point_of(range: impl OneSidedRange<usize>) -> Option<(Direction, usize)> { - use Bound::*; - - Some(match (range.start_bound(), range.end_bound()) { - (Unbounded, Excluded(i)) => (Direction::Front, *i), - (Unbounded, Included(i)) => (Direction::Front, i.checked_add(1)?), - (Excluded(i), Unbounded) => (Direction::Back, i.checked_add(1)?), - (Included(i), Unbounded) => (Direction::Back, *i), - _ => unreachable!(), + use OneSidedRangeBound::{End, EndInclusive, StartInclusive}; + + Some(match range.bound() { + (StartInclusive, i) => (Direction::Back, i), + (End, i) => (Direction::Front, i), + (EndInclusive, i) => (Direction::Front, i.checked_add(1)?), }) } |
