Skip to content

Commit 9f1f428

Browse files
authored
Rollup merge of #88502 - ibraheemdev:slice-take, r=dtolnay
Add slice take methods Revival of #62282 This PR adds the following slice methods: - `take` - `take_mut` - `take_first` - `take_first_mut` - `take_last` - `take_last_mut` r? `@LukasKalbertodt`
2 parents f04a2f4 + 8db85a3 commit 9f1f428

File tree

5 files changed

+394
-1
lines changed

5 files changed

+394
-1
lines changed

library/core/src/ops/mod.rs

+3
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,9 @@ pub use self::range::{Range, RangeFrom, RangeFull, RangeTo};
181181
#[stable(feature = "inclusive_range", since = "1.26.0")]
182182
pub use self::range::{Bound, RangeBounds, RangeInclusive, RangeToInclusive};
183183

184+
#[unstable(feature = "one_sided_range", issue = "69780")]
185+
pub use self::range::OneSidedRange;
186+
184187
#[unstable(feature = "try_trait_v2", issue = "84277")]
185188
pub use self::try_trait::{FromResidual, Try};
186189

library/core/src/ops/range.rs

+18
Original file line numberDiff line numberDiff line change
@@ -971,3 +971,21 @@ impl<T> RangeBounds<T> for RangeToInclusive<&T> {
971971
Included(self.end)
972972
}
973973
}
974+
975+
/// `OneSidedRange` is implemented for built-in range types that are unbounded
976+
/// on one side. For example, `a..`, `..b` and `..=c` implement `OneSidedRange`,
977+
/// but `..`, `d..e`, and `f..=g` do not.
978+
///
979+
/// Types that implement `OneSidedRange<T>` must return `Bound::Unbounded`
980+
/// from one of `RangeBounds::start_bound` or `RangeBounds::end_bound`.
981+
#[unstable(feature = "one_sided_range", issue = "69780")]
982+
pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> {}
983+
984+
#[unstable(feature = "one_sided_range", issue = "69780")]
985+
impl<T> OneSidedRange<T> for RangeTo<T> where Self: RangeBounds<T> {}
986+
987+
#[unstable(feature = "one_sided_range", issue = "69780")]
988+
impl<T> OneSidedRange<T> for RangeFrom<T> where Self: RangeBounds<T> {}
989+
990+
#[unstable(feature = "one_sided_range", issue = "69780")]
991+
impl<T> OneSidedRange<T> for RangeToInclusive<T> where Self: RangeBounds<T> {}

library/core/src/slice/mod.rs

+263-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use crate::cmp::Ordering::{self, Greater, Less};
1010
use crate::marker::Copy;
1111
use crate::mem;
1212
use crate::num::NonZeroUsize;
13-
use crate::ops::{FnMut, Range, RangeBounds};
13+
use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds};
1414
use crate::option::Option;
1515
use crate::option::Option::{None, Some};
1616
use crate::ptr;
@@ -82,6 +82,29 @@ pub use index::range;
8282
#[unstable(feature = "inherent_ascii_escape", issue = "77174")]
8383
pub use ascii::EscapeAscii;
8484

85+
/// Calculates the direction and split point of a one-sided range.
86+
///
87+
/// This is a helper function for `take` and `take_mut` that returns
88+
/// the direction of the split (front or back) as well as the index at
89+
/// which to split. Returns `None` if the split index would overflow.
90+
#[inline]
91+
fn split_point_of(range: impl OneSidedRange<usize>) -> Option<(Direction, usize)> {
92+
use Bound::*;
93+
94+
Some(match (range.start_bound(), range.end_bound()) {
95+
(Unbounded, Excluded(i)) => (Direction::Front, *i),
96+
(Unbounded, Included(i)) => (Direction::Front, i.checked_add(1)?),
97+
(Excluded(i), Unbounded) => (Direction::Back, i.checked_add(1)?),
98+
(Included(i), Unbounded) => (Direction::Back, *i),
99+
_ => unreachable!(),
100+
})
101+
}
102+
103+
enum Direction {
104+
Front,
105+
Back,
106+
}
107+
85108
#[lang = "slice"]
86109
#[cfg(not(test))]
87110
impl<T> [T] {
@@ -3517,6 +3540,245 @@ impl<T> [T] {
35173540
{
35183541
self.binary_search_by(|x| if pred(x) { Less } else { Greater }).unwrap_or_else(|i| i)
35193542
}
3543+
3544+
/// Removes the subslice corresponding to the given range
3545+
/// and returns a reference to it.
3546+
///
3547+
/// Returns `None` and does not modify the slice if the given
3548+
/// range is out of bounds.
3549+
///
3550+
/// Note that this method only accepts one-sided ranges such as
3551+
/// `2..` or `..6`, but not `2..6`.
3552+
///
3553+
/// # Examples
3554+
///
3555+
/// Taking the first three elements of a slice:
3556+
///
3557+
/// ```
3558+
/// #![feature(slice_take)]
3559+
///
3560+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
3561+
/// let mut first_three = slice.take(..3).unwrap();
3562+
///
3563+
/// assert_eq!(slice, &['d']);
3564+
/// assert_eq!(first_three, &['a', 'b', 'c']);
3565+
/// ```
3566+
///
3567+
/// Taking the last two elements of a slice:
3568+
///
3569+
/// ```
3570+
/// #![feature(slice_take)]
3571+
///
3572+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
3573+
/// let mut tail = slice.take(2..).unwrap();
3574+
///
3575+
/// assert_eq!(slice, &['a', 'b']);
3576+
/// assert_eq!(tail, &['c', 'd']);
3577+
/// ```
3578+
///
3579+
/// Getting `None` when `range` is out of bounds:
3580+
///
3581+
/// ```
3582+
/// #![feature(slice_take)]
3583+
///
3584+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
3585+
///
3586+
/// assert_eq!(None, slice.take(5..));
3587+
/// assert_eq!(None, slice.take(..5));
3588+
/// assert_eq!(None, slice.take(..=4));
3589+
/// let expected: &[char] = &['a', 'b', 'c', 'd'];
3590+
/// assert_eq!(Some(expected), slice.take(..4));
3591+
/// ```
3592+
#[inline]
3593+
#[must_use = "method does not modify the slice if the range is out of bounds"]
3594+
#[unstable(feature = "slice_take", issue = "62280")]
3595+
pub fn take<'a, R: OneSidedRange<usize>>(self: &mut &'a Self, range: R) -> Option<&'a Self> {
3596+
let (direction, split_index) = split_point_of(range)?;
3597+
if split_index > self.len() {
3598+
return None;
3599+
}
3600+
let (front, back) = self.split_at(split_index);
3601+
match direction {
3602+
Direction::Front => {
3603+
*self = back;
3604+
Some(front)
3605+
}
3606+
Direction::Back => {
3607+
*self = front;
3608+
Some(back)
3609+
}
3610+
}
3611+
}
3612+
3613+
/// Removes the subslice corresponding to the given range
3614+
/// and returns a mutable reference to it.
3615+
///
3616+
/// Returns `None` and does not modify the slice if the given
3617+
/// range is out of bounds.
3618+
///
3619+
/// Note that this method only accepts one-sided ranges such as
3620+
/// `2..` or `..6`, but not `2..6`.
3621+
///
3622+
/// # Examples
3623+
///
3624+
/// Taking the first three elements of a slice:
3625+
///
3626+
/// ```
3627+
/// #![feature(slice_take)]
3628+
///
3629+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3630+
/// let mut first_three = slice.take_mut(..3).unwrap();
3631+
///
3632+
/// assert_eq!(slice, &mut ['d']);
3633+
/// assert_eq!(first_three, &mut ['a', 'b', 'c']);
3634+
/// ```
3635+
///
3636+
/// Taking the last two elements of a slice:
3637+
///
3638+
/// ```
3639+
/// #![feature(slice_take)]
3640+
///
3641+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3642+
/// let mut tail = slice.take_mut(2..).unwrap();
3643+
///
3644+
/// assert_eq!(slice, &mut ['a', 'b']);
3645+
/// assert_eq!(tail, &mut ['c', 'd']);
3646+
/// ```
3647+
///
3648+
/// Getting `None` when `range` is out of bounds:
3649+
///
3650+
/// ```
3651+
/// #![feature(slice_take)]
3652+
///
3653+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3654+
///
3655+
/// assert_eq!(None, slice.take_mut(5..));
3656+
/// assert_eq!(None, slice.take_mut(..5));
3657+
/// assert_eq!(None, slice.take_mut(..=4));
3658+
/// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3659+
/// assert_eq!(Some(expected), slice.take_mut(..4));
3660+
/// ```
3661+
#[inline]
3662+
#[must_use = "method does not modify the slice if the range is out of bounds"]
3663+
#[unstable(feature = "slice_take", issue = "62280")]
3664+
pub fn take_mut<'a, R: OneSidedRange<usize>>(
3665+
self: &mut &'a mut Self,
3666+
range: R,
3667+
) -> Option<&'a mut Self> {
3668+
let (direction, split_index) = split_point_of(range)?;
3669+
if split_index > self.len() {
3670+
return None;
3671+
}
3672+
let (front, back) = mem::take(self).split_at_mut(split_index);
3673+
match direction {
3674+
Direction::Front => {
3675+
*self = back;
3676+
Some(front)
3677+
}
3678+
Direction::Back => {
3679+
*self = front;
3680+
Some(back)
3681+
}
3682+
}
3683+
}
3684+
3685+
/// Removes the first element of the slice and returns a reference
3686+
/// to it.
3687+
///
3688+
/// Returns `None` if the slice is empty.
3689+
///
3690+
/// # Examples
3691+
///
3692+
/// ```
3693+
/// #![feature(slice_take)]
3694+
///
3695+
/// let mut slice: &[_] = &['a', 'b', 'c'];
3696+
/// let first = slice.take_first().unwrap();
3697+
///
3698+
/// assert_eq!(slice, &['b', 'c']);
3699+
/// assert_eq!(first, &'a');
3700+
/// ```
3701+
#[inline]
3702+
#[unstable(feature = "slice_take", issue = "62280")]
3703+
pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> {
3704+
let (first, rem) = self.split_first()?;
3705+
*self = rem;
3706+
Some(first)
3707+
}
3708+
3709+
/// Removes the first element of the slice and returns a mutable
3710+
/// reference to it.
3711+
///
3712+
/// Returns `None` if the slice is empty.
3713+
///
3714+
/// # Examples
3715+
///
3716+
/// ```
3717+
/// #![feature(slice_take)]
3718+
///
3719+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
3720+
/// let first = slice.take_first_mut().unwrap();
3721+
/// *first = 'd';
3722+
///
3723+
/// assert_eq!(slice, &['b', 'c']);
3724+
/// assert_eq!(first, &'d');
3725+
/// ```
3726+
#[inline]
3727+
#[unstable(feature = "slice_take", issue = "62280")]
3728+
pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
3729+
let (first, rem) = mem::take(self).split_first_mut()?;
3730+
*self = rem;
3731+
Some(first)
3732+
}
3733+
3734+
/// Removes the last element of the slice and returns a reference
3735+
/// to it.
3736+
///
3737+
/// Returns `None` if the slice is empty.
3738+
///
3739+
/// # Examples
3740+
///
3741+
/// ```
3742+
/// #![feature(slice_take)]
3743+
///
3744+
/// let mut slice: &[_] = &['a', 'b', 'c'];
3745+
/// let last = slice.take_last().unwrap();
3746+
///
3747+
/// assert_eq!(slice, &['a', 'b']);
3748+
/// assert_eq!(last, &'c');
3749+
/// ```
3750+
#[inline]
3751+
#[unstable(feature = "slice_take", issue = "62280")]
3752+
pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> {
3753+
let (last, rem) = self.split_last()?;
3754+
*self = rem;
3755+
Some(last)
3756+
}
3757+
3758+
/// Removes the last element of the slice and returns a mutable
3759+
/// reference to it.
3760+
///
3761+
/// Returns `None` if the slice is empty.
3762+
///
3763+
/// # Examples
3764+
///
3765+
/// ```
3766+
/// #![feature(slice_take)]
3767+
///
3768+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
3769+
/// let last = slice.take_last_mut().unwrap();
3770+
/// *last = 'd';
3771+
///
3772+
/// assert_eq!(slice, &['a', 'b']);
3773+
/// assert_eq!(last, &'d');
3774+
/// ```
3775+
#[inline]
3776+
#[unstable(feature = "slice_take", issue = "62280")]
3777+
pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
3778+
let (last, rem) = mem::take(self).split_last_mut()?;
3779+
*self = rem;
3780+
Some(last)
3781+
}
35203782
}
35213783

35223784
trait CloneFromSpec<T> {

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
#![feature(pattern)]
3737
#![feature(sort_internals)]
3838
#![feature(slice_partition_at_index)]
39+
#![feature(slice_take)]
3940
#![feature(maybe_uninit_uninit_array)]
4041
#![feature(maybe_uninit_array_assume_init)]
4142
#![feature(maybe_uninit_extra)]

0 commit comments

Comments
 (0)