Skip to content

Commit 8db85a3

Browse files
committed
add slice take methods
1 parent e90c5fb commit 8db85a3

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] {
@@ -3576,6 +3599,245 @@ impl<T> [T] {
35763599
{
35773600
self.binary_search_by(|x| if pred(x) { Less } else { Greater }).unwrap_or_else(|i| i)
35783601
}
3602+
3603+
/// Removes the subslice corresponding to the given range
3604+
/// and returns a reference to it.
3605+
///
3606+
/// Returns `None` and does not modify the slice if the given
3607+
/// range is out of bounds.
3608+
///
3609+
/// Note that this method only accepts one-sided ranges such as
3610+
/// `2..` or `..6`, but not `2..6`.
3611+
///
3612+
/// # Examples
3613+
///
3614+
/// Taking the first three elements of a slice:
3615+
///
3616+
/// ```
3617+
/// #![feature(slice_take)]
3618+
///
3619+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
3620+
/// let mut first_three = slice.take(..3).unwrap();
3621+
///
3622+
/// assert_eq!(slice, &['d']);
3623+
/// assert_eq!(first_three, &['a', 'b', 'c']);
3624+
/// ```
3625+
///
3626+
/// Taking the last two elements of a slice:
3627+
///
3628+
/// ```
3629+
/// #![feature(slice_take)]
3630+
///
3631+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
3632+
/// let mut tail = slice.take(2..).unwrap();
3633+
///
3634+
/// assert_eq!(slice, &['a', 'b']);
3635+
/// assert_eq!(tail, &['c', 'd']);
3636+
/// ```
3637+
///
3638+
/// Getting `None` when `range` is out of bounds:
3639+
///
3640+
/// ```
3641+
/// #![feature(slice_take)]
3642+
///
3643+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
3644+
///
3645+
/// assert_eq!(None, slice.take(5..));
3646+
/// assert_eq!(None, slice.take(..5));
3647+
/// assert_eq!(None, slice.take(..=4));
3648+
/// let expected: &[char] = &['a', 'b', 'c', 'd'];
3649+
/// assert_eq!(Some(expected), slice.take(..4));
3650+
/// ```
3651+
#[inline]
3652+
#[must_use = "method does not modify the slice if the range is out of bounds"]
3653+
#[unstable(feature = "slice_take", issue = "62280")]
3654+
pub fn take<'a, R: OneSidedRange<usize>>(self: &mut &'a Self, range: R) -> Option<&'a Self> {
3655+
let (direction, split_index) = split_point_of(range)?;
3656+
if split_index > self.len() {
3657+
return None;
3658+
}
3659+
let (front, back) = self.split_at(split_index);
3660+
match direction {
3661+
Direction::Front => {
3662+
*self = back;
3663+
Some(front)
3664+
}
3665+
Direction::Back => {
3666+
*self = front;
3667+
Some(back)
3668+
}
3669+
}
3670+
}
3671+
3672+
/// Removes the subslice corresponding to the given range
3673+
/// and returns a mutable reference to it.
3674+
///
3675+
/// Returns `None` and does not modify the slice if the given
3676+
/// range is out of bounds.
3677+
///
3678+
/// Note that this method only accepts one-sided ranges such as
3679+
/// `2..` or `..6`, but not `2..6`.
3680+
///
3681+
/// # Examples
3682+
///
3683+
/// Taking the first three elements of a slice:
3684+
///
3685+
/// ```
3686+
/// #![feature(slice_take)]
3687+
///
3688+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3689+
/// let mut first_three = slice.take_mut(..3).unwrap();
3690+
///
3691+
/// assert_eq!(slice, &mut ['d']);
3692+
/// assert_eq!(first_three, &mut ['a', 'b', 'c']);
3693+
/// ```
3694+
///
3695+
/// Taking the last two elements of a slice:
3696+
///
3697+
/// ```
3698+
/// #![feature(slice_take)]
3699+
///
3700+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3701+
/// let mut tail = slice.take_mut(2..).unwrap();
3702+
///
3703+
/// assert_eq!(slice, &mut ['a', 'b']);
3704+
/// assert_eq!(tail, &mut ['c', 'd']);
3705+
/// ```
3706+
///
3707+
/// Getting `None` when `range` is out of bounds:
3708+
///
3709+
/// ```
3710+
/// #![feature(slice_take)]
3711+
///
3712+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3713+
///
3714+
/// assert_eq!(None, slice.take_mut(5..));
3715+
/// assert_eq!(None, slice.take_mut(..5));
3716+
/// assert_eq!(None, slice.take_mut(..=4));
3717+
/// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3718+
/// assert_eq!(Some(expected), slice.take_mut(..4));
3719+
/// ```
3720+
#[inline]
3721+
#[must_use = "method does not modify the slice if the range is out of bounds"]
3722+
#[unstable(feature = "slice_take", issue = "62280")]
3723+
pub fn take_mut<'a, R: OneSidedRange<usize>>(
3724+
self: &mut &'a mut Self,
3725+
range: R,
3726+
) -> Option<&'a mut Self> {
3727+
let (direction, split_index) = split_point_of(range)?;
3728+
if split_index > self.len() {
3729+
return None;
3730+
}
3731+
let (front, back) = mem::take(self).split_at_mut(split_index);
3732+
match direction {
3733+
Direction::Front => {
3734+
*self = back;
3735+
Some(front)
3736+
}
3737+
Direction::Back => {
3738+
*self = front;
3739+
Some(back)
3740+
}
3741+
}
3742+
}
3743+
3744+
/// Removes the first element of the slice and returns a reference
3745+
/// to it.
3746+
///
3747+
/// Returns `None` if the slice is empty.
3748+
///
3749+
/// # Examples
3750+
///
3751+
/// ```
3752+
/// #![feature(slice_take)]
3753+
///
3754+
/// let mut slice: &[_] = &['a', 'b', 'c'];
3755+
/// let first = slice.take_first().unwrap();
3756+
///
3757+
/// assert_eq!(slice, &['b', 'c']);
3758+
/// assert_eq!(first, &'a');
3759+
/// ```
3760+
#[inline]
3761+
#[unstable(feature = "slice_take", issue = "62280")]
3762+
pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> {
3763+
let (first, rem) = self.split_first()?;
3764+
*self = rem;
3765+
Some(first)
3766+
}
3767+
3768+
/// Removes the first element of the slice and returns a mutable
3769+
/// reference to it.
3770+
///
3771+
/// Returns `None` if the slice is empty.
3772+
///
3773+
/// # Examples
3774+
///
3775+
/// ```
3776+
/// #![feature(slice_take)]
3777+
///
3778+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
3779+
/// let first = slice.take_first_mut().unwrap();
3780+
/// *first = 'd';
3781+
///
3782+
/// assert_eq!(slice, &['b', 'c']);
3783+
/// assert_eq!(first, &'d');
3784+
/// ```
3785+
#[inline]
3786+
#[unstable(feature = "slice_take", issue = "62280")]
3787+
pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
3788+
let (first, rem) = mem::take(self).split_first_mut()?;
3789+
*self = rem;
3790+
Some(first)
3791+
}
3792+
3793+
/// Removes the last element of the slice and returns a reference
3794+
/// to it.
3795+
///
3796+
/// Returns `None` if the slice is empty.
3797+
///
3798+
/// # Examples
3799+
///
3800+
/// ```
3801+
/// #![feature(slice_take)]
3802+
///
3803+
/// let mut slice: &[_] = &['a', 'b', 'c'];
3804+
/// let last = slice.take_last().unwrap();
3805+
///
3806+
/// assert_eq!(slice, &['a', 'b']);
3807+
/// assert_eq!(last, &'c');
3808+
/// ```
3809+
#[inline]
3810+
#[unstable(feature = "slice_take", issue = "62280")]
3811+
pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> {
3812+
let (last, rem) = self.split_last()?;
3813+
*self = rem;
3814+
Some(last)
3815+
}
3816+
3817+
/// Removes the last element of the slice and returns a mutable
3818+
/// reference to it.
3819+
///
3820+
/// Returns `None` if the slice is empty.
3821+
///
3822+
/// # Examples
3823+
///
3824+
/// ```
3825+
/// #![feature(slice_take)]
3826+
///
3827+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
3828+
/// let last = slice.take_last_mut().unwrap();
3829+
/// *last = 'd';
3830+
///
3831+
/// assert_eq!(slice, &['a', 'b']);
3832+
/// assert_eq!(last, &'d');
3833+
/// ```
3834+
#[inline]
3835+
#[unstable(feature = "slice_take", issue = "62280")]
3836+
pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
3837+
let (last, rem) = mem::take(self).split_last_mut()?;
3838+
*self = rem;
3839+
Some(last)
3840+
}
35793841
}
35803842

35813843
trait CloneFromSpec<T> {

library/core/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#![feature(pattern)]
3535
#![feature(sort_internals)]
3636
#![feature(slice_partition_at_index)]
37+
#![feature(slice_take)]
3738
#![feature(maybe_uninit_uninit_array)]
3839
#![feature(maybe_uninit_array_assume_init)]
3940
#![feature(maybe_uninit_extra)]

0 commit comments

Comments
 (0)