Skip to content

Commit

Permalink
Rollup merge of #136555 - cramertj:split_off, r=dtolnay
Browse files Browse the repository at this point in the history
Rename `slice::take...` methods to `split_off...`

This rename was discussed and recommended in a recent t-libs meeting.

cc #62280

There's an additional commit here which modifies internals of unstable `OneSidedRange` APIs in order to implement `split_off` methods in a panic-free way (remove `unreachable!()`) as recommended in https://github.com/rust-lang/rust/pull/88502/files#r760177240. I can split this out into a separate PR if needed.
  • Loading branch information
jieyouxu authored Feb 5, 2025
2 parents f30ce21 + 836a989 commit fd4623b
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 95 deletions.
4 changes: 2 additions & 2 deletions library/core/src/ops/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")]
Expand Down
46 changes: 42 additions & 4 deletions library/core/src/ops/range.rs
Original file line number Diff line number Diff line change
Expand Up @@ -979,20 +979,58 @@ 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.
///
/// 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)
}
}
69 changes: 35 additions & 34 deletions library/core/src/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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)?),
})
}

Expand Down Expand Up @@ -4294,25 +4292,25 @@ impl<T> [T] {
///
/// # Examples
///
/// Taking the first three elements of a slice:
/// Splitting off the first three elements of a slice:
///
/// ```
/// #![feature(slice_take)]
///
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
/// let mut first_three = slice.take(..3).unwrap();
/// let mut first_three = slice.split_off(..3).unwrap();
///
/// assert_eq!(slice, &['d']);
/// assert_eq!(first_three, &['a', 'b', 'c']);
/// ```
///
/// Taking the last two elements of a slice:
/// Splitting off the last two elements of a slice:
///
/// ```
/// #![feature(slice_take)]
///
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
/// let mut tail = slice.take(2..).unwrap();
/// let mut tail = slice.split_off(2..).unwrap();
///
/// assert_eq!(slice, &['a', 'b']);
/// assert_eq!(tail, &['c', 'd']);
Expand All @@ -4325,16 +4323,19 @@ impl<T> [T] {
///
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
///
/// assert_eq!(None, slice.take(5..));
/// assert_eq!(None, slice.take(..5));
/// assert_eq!(None, slice.take(..=4));
/// assert_eq!(None, slice.split_off(5..));
/// assert_eq!(None, slice.split_off(..5));
/// assert_eq!(None, slice.split_off(..=4));
/// let expected: &[char] = &['a', 'b', 'c', 'd'];
/// assert_eq!(Some(expected), slice.take(..4));
/// assert_eq!(Some(expected), slice.split_off(..4));
/// ```
#[inline]
#[must_use = "method does not modify the slice if the range is out of bounds"]
#[unstable(feature = "slice_take", issue = "62280")]
pub fn take<'a, R: OneSidedRange<usize>>(self: &mut &'a Self, range: R) -> Option<&'a Self> {
pub fn split_off<'a, R: OneSidedRange<usize>>(
self: &mut &'a Self,
range: R,
) -> Option<&'a Self> {
let (direction, split_index) = split_point_of(range)?;
if split_index > self.len() {
return None;
Expand Down Expand Up @@ -4363,13 +4364,13 @@ impl<T> [T] {
///
/// # Examples
///
/// Taking the first three elements of a slice:
/// Splitting off the first three elements of a slice:
///
/// ```
/// #![feature(slice_take)]
///
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
/// let mut first_three = slice.take_mut(..3).unwrap();
/// let mut first_three = slice.split_off_mut(..3).unwrap();
///
/// assert_eq!(slice, &mut ['d']);
/// assert_eq!(first_three, &mut ['a', 'b', 'c']);
Expand All @@ -4381,7 +4382,7 @@ impl<T> [T] {
/// #![feature(slice_take)]
///
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
/// let mut tail = slice.take_mut(2..).unwrap();
/// let mut tail = slice.split_off_mut(2..).unwrap();
///
/// assert_eq!(slice, &mut ['a', 'b']);
/// assert_eq!(tail, &mut ['c', 'd']);
Expand All @@ -4394,16 +4395,16 @@ impl<T> [T] {
///
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
///
/// assert_eq!(None, slice.take_mut(5..));
/// assert_eq!(None, slice.take_mut(..5));
/// assert_eq!(None, slice.take_mut(..=4));
/// assert_eq!(None, slice.split_off_mut(5..));
/// assert_eq!(None, slice.split_off_mut(..5));
/// assert_eq!(None, slice.split_off_mut(..=4));
/// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd'];
/// assert_eq!(Some(expected), slice.take_mut(..4));
/// assert_eq!(Some(expected), slice.split_off_mut(..4));
/// ```
#[inline]
#[must_use = "method does not modify the slice if the range is out of bounds"]
#[unstable(feature = "slice_take", issue = "62280")]
pub fn take_mut<'a, R: OneSidedRange<usize>>(
pub fn split_off_mut<'a, R: OneSidedRange<usize>>(
self: &mut &'a mut Self,
range: R,
) -> Option<&'a mut Self> {
Expand Down Expand Up @@ -4435,14 +4436,14 @@ impl<T> [T] {
/// #![feature(slice_take)]
///
/// let mut slice: &[_] = &['a', 'b', 'c'];
/// let first = slice.take_first().unwrap();
/// let first = slice.split_off_first().unwrap();
///
/// assert_eq!(slice, &['b', 'c']);
/// assert_eq!(first, &'a');
/// ```
#[inline]
#[unstable(feature = "slice_take", issue = "62280")]
pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> {
pub fn split_off_first<'a>(self: &mut &'a Self) -> Option<&'a T> {
let (first, rem) = self.split_first()?;
*self = rem;
Some(first)
Expand All @@ -4459,15 +4460,15 @@ impl<T> [T] {
/// #![feature(slice_take)]
///
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
/// let first = slice.take_first_mut().unwrap();
/// let first = slice.split_off_first_mut().unwrap();
/// *first = 'd';
///
/// assert_eq!(slice, &['b', 'c']);
/// assert_eq!(first, &'d');
/// ```
#[inline]
#[unstable(feature = "slice_take", issue = "62280")]
pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
pub fn split_off_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
let (first, rem) = mem::take(self).split_first_mut()?;
*self = rem;
Some(first)
Expand All @@ -4484,14 +4485,14 @@ impl<T> [T] {
/// #![feature(slice_take)]
///
/// let mut slice: &[_] = &['a', 'b', 'c'];
/// let last = slice.take_last().unwrap();
/// let last = slice.split_off_last().unwrap();
///
/// assert_eq!(slice, &['a', 'b']);
/// assert_eq!(last, &'c');
/// ```
#[inline]
#[unstable(feature = "slice_take", issue = "62280")]
pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> {
pub fn split_off_last<'a>(self: &mut &'a Self) -> Option<&'a T> {
let (last, rem) = self.split_last()?;
*self = rem;
Some(last)
Expand All @@ -4508,15 +4509,15 @@ impl<T> [T] {
/// #![feature(slice_take)]
///
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
/// let last = slice.take_last_mut().unwrap();
/// let last = slice.split_off_last_mut().unwrap();
/// *last = 'd';
///
/// assert_eq!(slice, &['a', 'b']);
/// assert_eq!(last, &'d');
/// ```
#[inline]
#[unstable(feature = "slice_take", issue = "62280")]
pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
pub fn split_off_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
let (last, rem) = mem::take(self).split_last_mut()?;
*self = rem;
Some(last)
Expand Down
Loading

0 comments on commit fd4623b

Please sign in to comment.