Skip to content

Commit bd417a4

Browse files
cramertjtimvermeulen
authored andcommitted
Add take_... functions to slices
1 parent 7e9a36f commit bd417a4

File tree

5 files changed

+366
-1
lines changed

5 files changed

+366
-1
lines changed

library/core/src/ops/mod.rs

Lines changed: 3 additions & 0 deletions
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", issue = "42327")]
185188
pub use self::r#try::Try;
186189

library/core/src/ops/range.rs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1004,3 +1004,21 @@ impl<T> RangeBounds<T> for RangeToInclusive<&T> {
10041004
Included(self.end)
10051005
}
10061006
}
1007+
1008+
/// `OneSidedRange` is implemented by Rust's built-in range types which
1009+
/// are unbounded on one side. For example, `a..`, `..b` and `..=c` implement
1010+
/// `OneSidedRange`, but `..`, `d..e`, and `f..=g` do not.
1011+
///
1012+
/// Types which implement `OneSidedRange<T>` must return `Bound::Unbounded`
1013+
/// from exactly one of `RangeBounds::start_bound` and `RangeBounds::end_bound`.
1014+
#[unstable(feature = "one_sided_range", issue = "69780")]
1015+
pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> {}
1016+
1017+
#[unstable(feature = "one_sided_range", issue = "69780")]
1018+
impl<T> OneSidedRange<T> for RangeTo<T> where Self: RangeBounds<T> {}
1019+
1020+
#[unstable(feature = "one_sided_range", issue = "69780")]
1021+
impl<T> OneSidedRange<T> for RangeFrom<T> where Self: RangeBounds<T> {}
1022+
1023+
#[unstable(feature = "one_sided_range", issue = "69780")]
1024+
impl<T> OneSidedRange<T> for RangeToInclusive<T> where Self: RangeBounds<T> {}

library/core/src/slice/mod.rs

Lines changed: 240 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less};
1212
use crate::marker::Copy;
1313
use crate::mem;
1414
use crate::num::NonZeroUsize;
15-
use crate::ops::{FnMut, Range, RangeBounds};
15+
use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds};
1616
use crate::option::Option;
1717
use crate::option::Option::{None, Some};
1818
use crate::ptr;
@@ -73,6 +73,24 @@ pub use sort::heapsort;
7373
#[stable(feature = "slice_get_slice", since = "1.28.0")]
7474
pub use index::SliceIndex;
7575

76+
/// Calculates the direction and split point of a one-sided range.
77+
///
78+
/// Helper for `take` and `take_mut` which returns a boolean
79+
/// indicating whether the front of the split is being taken
80+
/// (as opposed to the back), as well as a number indicating the
81+
/// index at which to split. Returns `None` if the split index would
82+
/// overflow `usize`.
83+
#[inline]
84+
fn take_split_point(range: impl OneSidedRange<usize>) -> Option<(bool, usize)> {
85+
Some(match (range.start_bound(), range.end_bound()) {
86+
(Bound::Unbounded, Bound::Excluded(i)) => (true, *i),
87+
(Bound::Unbounded, Bound::Included(i)) => (true, i.checked_add(1)?),
88+
(Bound::Excluded(i), Bound::Unbounded) => (false, i.checked_add(1)?),
89+
(Bound::Included(i), Bound::Unbounded) => (false, *i),
90+
_ => unreachable!(),
91+
})
92+
}
93+
7694
#[lang = "slice"]
7795
#[cfg(not(test))]
7896
impl<T> [T] {
@@ -3169,6 +3187,227 @@ impl<T> [T] {
31693187

31703188
left
31713189
}
3190+
3191+
/// Removes and returns the portion of the slice specified by `range`.
3192+
///
3193+
/// If the provided `range` starts or ends outside of the slice,
3194+
/// `None` is returned and the slice is not modified.
3195+
///
3196+
/// # Examples
3197+
///
3198+
/// Taking the first three items from a slice (via `..3`):
3199+
///
3200+
/// ```
3201+
/// #![feature(slice_take)]
3202+
///
3203+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
3204+
/// let mut first_three = slice.take(..3).unwrap();
3205+
///
3206+
/// assert_eq!(slice, &['d']);
3207+
/// assert_eq!(first_three, &['a', 'b', 'c']);
3208+
/// ```
3209+
///
3210+
/// Taking the tail of a slice starting at index two (via `2..`):
3211+
///
3212+
/// ```
3213+
/// #![feature(slice_take)]
3214+
///
3215+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
3216+
/// let mut tail = slice.take(2..).unwrap();
3217+
///
3218+
/// assert_eq!(slice, &['a', 'b']);
3219+
/// assert_eq!(tail, &['c', 'd']);
3220+
/// ```
3221+
///
3222+
/// Getting `None` when `range` starts or ends outside of the slice:
3223+
///
3224+
/// ```
3225+
/// #![feature(slice_take)]
3226+
///
3227+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
3228+
///
3229+
/// assert_eq!(None, slice.take(5..));
3230+
/// assert_eq!(None, slice.take(..5));
3231+
/// assert_eq!(None, slice.take(..=4));
3232+
/// let expected: &[char] = &['a', 'b', 'c', 'd'];
3233+
/// assert_eq!(Some(expected), slice.take(..4));
3234+
/// ```
3235+
#[inline]
3236+
#[unstable(feature = "slice_take", issue = "62280")]
3237+
pub fn take<'a, R: OneSidedRange<usize>>(self: &mut &'a Self, range: R) -> Option<&'a Self> {
3238+
let (taking_front, split_index) = take_split_point(range)?;
3239+
if split_index > self.len() {
3240+
return None;
3241+
}
3242+
let original = crate::mem::take(self);
3243+
let (front, back) = original.split_at(split_index);
3244+
if taking_front {
3245+
*self = back;
3246+
Some(front)
3247+
} else {
3248+
*self = front;
3249+
Some(back)
3250+
}
3251+
}
3252+
3253+
/// Removes and returns the portion of the mutable slice specified by `range`.
3254+
///
3255+
/// If the provided `range` starts or ends outside of the slice,
3256+
/// `None` is returned and the slice is not modified.
3257+
///
3258+
/// # Examples
3259+
///
3260+
/// Taking the first three items from a slice (via `..3`):
3261+
///
3262+
/// ```
3263+
/// #![feature(slice_take)]
3264+
///
3265+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3266+
/// let mut first_three = slice.take_mut(..3).unwrap();
3267+
///
3268+
/// assert_eq!(slice, &mut ['d']);
3269+
/// assert_eq!(first_three, &mut ['a', 'b', 'c']);
3270+
/// ```
3271+
///
3272+
/// Taking the tail of a slice starting at index two (via `2..`):
3273+
///
3274+
/// ```
3275+
/// #![feature(slice_take)]
3276+
///
3277+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3278+
/// let mut tail = slice.take_mut(2..).unwrap();
3279+
///
3280+
/// assert_eq!(slice, &mut ['a', 'b']);
3281+
/// assert_eq!(tail, &mut ['c', 'd']);
3282+
/// ```
3283+
///
3284+
/// Getting `None` when `range` starts or ends outside of the slice:
3285+
///
3286+
/// ```
3287+
/// #![feature(slice_take)]
3288+
///
3289+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3290+
///
3291+
/// assert_eq!(None, slice.take_mut(5..));
3292+
/// assert_eq!(None, slice.take_mut(..5));
3293+
/// assert_eq!(None, slice.take_mut(..=4));
3294+
/// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3295+
/// assert_eq!(Some(expected), slice.take_mut(..4));
3296+
/// ```
3297+
#[inline]
3298+
#[unstable(feature = "slice_take", issue = "62280")]
3299+
pub fn take_mut<'a, R: OneSidedRange<usize>>(
3300+
self: &mut &'a mut Self,
3301+
range: R,
3302+
) -> Option<&'a mut Self> {
3303+
let (taking_front, split_index) = take_split_point(range)?;
3304+
if split_index > self.len() {
3305+
return None;
3306+
}
3307+
let original = crate::mem::take(self);
3308+
let (front, back) = original.split_at_mut(split_index);
3309+
if taking_front {
3310+
*self = back;
3311+
Some(front)
3312+
} else {
3313+
*self = front;
3314+
Some(back)
3315+
}
3316+
}
3317+
3318+
/// Takes the first element out of the slice.
3319+
///
3320+
/// Returns a reference pointing to the first element of the old slice.
3321+
///
3322+
/// Returns `None` if the slice is empty.
3323+
///
3324+
/// # Examples
3325+
///
3326+
/// ```
3327+
/// #![feature(slice_take)]
3328+
///
3329+
/// let mut slice: &[_] = &['a', 'b', 'c'];
3330+
/// let first = slice.take_first().unwrap();
3331+
///
3332+
/// assert_eq!(slice, &['b', 'c']);
3333+
/// assert_eq!(first, &'a');
3334+
/// ```
3335+
#[inline]
3336+
#[unstable(feature = "slice_take", issue = "62280")]
3337+
pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> {
3338+
self.take(..=0).map(|res| &res[0])
3339+
}
3340+
3341+
/// Takes the first element out of the mutable slice.
3342+
///
3343+
/// Returns a mutable reference pointing to the first element of the old slice.
3344+
///
3345+
/// Returns `None` if the slice is empty.
3346+
///
3347+
/// # Examples
3348+
///
3349+
/// ```
3350+
/// #![feature(slice_take)]
3351+
///
3352+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
3353+
/// let first = slice.take_first_mut().unwrap();
3354+
/// *first = 'd';
3355+
///
3356+
/// assert_eq!(slice, &['b', 'c']);
3357+
/// assert_eq!(first, &'d');
3358+
/// ```
3359+
#[inline]
3360+
#[unstable(feature = "slice_take", issue = "62280")]
3361+
pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
3362+
self.take_mut(..=0).map(|res| &mut res[0])
3363+
}
3364+
3365+
/// Takes the last element out of the slice.
3366+
///
3367+
/// Returns a reference pointing to the last element of the old slice.
3368+
///
3369+
/// Returns `None` if the slice is empty.
3370+
///
3371+
/// # Examples
3372+
///
3373+
/// ```
3374+
/// #![feature(slice_take)]
3375+
///
3376+
/// let mut slice: &[_] = &['a', 'b', 'c'];
3377+
/// let last = slice.take_last().unwrap();
3378+
///
3379+
/// assert_eq!(slice, &['a', 'b']);
3380+
/// assert_eq!(last, &'c');
3381+
/// ```
3382+
#[inline]
3383+
#[unstable(feature = "slice_take", issue = "62280")]
3384+
pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> {
3385+
self.take((self.len() - 1)..).map(|res| &res[0])
3386+
}
3387+
3388+
/// Takes the last element out of the mutable slice.
3389+
///
3390+
/// Returns a mutable reference pointing to the last element of the old slice.
3391+
///
3392+
/// Returns `None` if the slice is empty.
3393+
///
3394+
/// # Examples
3395+
///
3396+
/// ```
3397+
/// #![feature(slice_take)]
3398+
///
3399+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
3400+
/// let last = slice.take_last_mut().unwrap();
3401+
/// *last = 'd';
3402+
///
3403+
/// assert_eq!(slice, &['a', 'b']);
3404+
/// assert_eq!(last, &'d');
3405+
/// ```
3406+
#[inline]
3407+
#[unstable(feature = "slice_take", issue = "62280")]
3408+
pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
3409+
self.take_mut((self.len() - 1)..).map(|res| &mut res[0])
3410+
}
31723411
}
31733412

31743413
#[stable(feature = "rust1", since = "1.0.0")]

library/core/tests/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
#![feature(try_trait)]
4040
#![feature(slice_internals)]
4141
#![feature(slice_partition_dedup)]
42+
#![feature(slice_take)]
4243
#![feature(int_error_matching)]
4344
#![feature(array_value_iter)]
4445
#![feature(iter_advance_by)]

0 commit comments

Comments
 (0)