Skip to content

Commit 87aaf0a

Browse files
cramertjtimvermeulen
authored andcommitted
Add take_... functions to slices
1 parent a2c82df commit 87aaf0a

File tree

5 files changed

+362
-1
lines changed

5 files changed

+362
-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
@@ -872,3 +872,21 @@ impl<T> RangeBounds<T> for RangeToInclusive<&T> {
872872
Included(self.end)
873873
}
874874
}
875+
876+
/// `OneSidedRange` is implemented by Rust's built-in range types which
877+
/// are unbounded on one side. For example, `a..`, `..b` and `..=c` implement
878+
/// `OneSidedRange`, but `..`, `d..e`, and `f..=g` do not.
879+
///
880+
/// Types which implement `OneSidedRange<T>` must return `Bound::Unbounded`
881+
/// from exactly one of `RangeBounds::start_bound` and `RangeBounds::end_bound`.
882+
#[unstable(feature = "one_sided_range", issue = "69780")]
883+
pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> {}
884+
885+
#[unstable(feature = "one_sided_range", issue = "69780")]
886+
impl<T> OneSidedRange<T> for RangeTo<T> where Self: RangeBounds<T> {}
887+
888+
#[unstable(feature = "one_sided_range", issue = "69780")]
889+
impl<T> OneSidedRange<T> for RangeFrom<T> where Self: RangeBounds<T> {}
890+
891+
#[unstable(feature = "one_sided_range", issue = "69780")]
892+
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
@@ -11,7 +11,7 @@
1111
use crate::cmp::Ordering::{self, Equal, Greater, Less};
1212
use crate::marker::Copy;
1313
use crate::mem;
14-
use crate::ops::{FnMut, Range, RangeBounds};
14+
use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds};
1515
use crate::option::Option;
1616
use crate::option::Option::{None, Some};
1717
use crate::ptr;
@@ -75,6 +75,24 @@ pub use index::SliceIndex;
7575
#[unstable(feature = "slice_check_range", issue = "76393")]
7676
pub use index::check_range;
7777

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

30603078
left
30613079
}
3080+
3081+
/// Removes and returns the portion of the slice specified by `range`.
3082+
///
3083+
/// If the provided `range` starts or ends outside of the slice,
3084+
/// `None` is returned and the slice is not modified.
3085+
///
3086+
/// # Examples
3087+
///
3088+
/// Taking the first three items from a slice (via `..3`):
3089+
///
3090+
/// ```
3091+
/// #![feature(slice_take)]
3092+
///
3093+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
3094+
/// let mut first_three = slice.take(..3).unwrap();
3095+
///
3096+
/// assert_eq!(slice, &['d']);
3097+
/// assert_eq!(first_three, &['a', 'b', 'c']);
3098+
/// ```
3099+
///
3100+
/// Taking the tail of a slice starting at index two (via `2..`):
3101+
///
3102+
/// ```
3103+
/// #![feature(slice_take)]
3104+
///
3105+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
3106+
/// let mut tail = slice.take(2..).unwrap();
3107+
///
3108+
/// assert_eq!(slice, &['a', 'b']);
3109+
/// assert_eq!(tail, &['c', 'd']);
3110+
/// ```
3111+
///
3112+
/// Getting `None` when `range` starts or ends outside of the slice:
3113+
///
3114+
/// ```
3115+
/// #![feature(slice_take)]
3116+
///
3117+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
3118+
///
3119+
/// assert_eq!(None, slice.take(5..));
3120+
/// assert_eq!(None, slice.take(..5));
3121+
/// assert_eq!(None, slice.take(..=4));
3122+
/// let expected: &[char] = &['a', 'b', 'c', 'd'];
3123+
/// assert_eq!(Some(expected), slice.take(..4));
3124+
/// ```
3125+
#[inline]
3126+
#[unstable(feature = "slice_take", issue = "62280")]
3127+
pub fn take<'a, R: OneSidedRange<usize>>(self: &mut &'a Self, range: R) -> Option<&'a Self> {
3128+
let (taking_front, split_index) = take_split_point(range)?;
3129+
if split_index > self.len() {
3130+
return None;
3131+
}
3132+
let original = crate::mem::take(self);
3133+
let (front, back) = original.split_at(split_index);
3134+
if taking_front {
3135+
*self = back;
3136+
Some(front)
3137+
} else {
3138+
*self = front;
3139+
Some(back)
3140+
}
3141+
}
3142+
3143+
/// Removes and returns the portion of the mutable slice specified by `range`.
3144+
///
3145+
/// If the provided `range` starts or ends outside of the slice,
3146+
/// `None` is returned and the slice is not modified.
3147+
///
3148+
/// # Examples
3149+
///
3150+
/// Taking the first three items from a slice (via `..3`):
3151+
///
3152+
/// ```
3153+
/// #![feature(slice_take)]
3154+
///
3155+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3156+
/// let mut first_three = slice.take_mut(..3).unwrap();
3157+
///
3158+
/// assert_eq!(slice, &mut ['d']);
3159+
/// assert_eq!(first_three, &mut ['a', 'b', 'c']);
3160+
/// ```
3161+
///
3162+
/// Taking the tail of a slice starting at index two (via `2..`):
3163+
///
3164+
/// ```
3165+
/// #![feature(slice_take)]
3166+
///
3167+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3168+
/// let mut tail = slice.take_mut(2..).unwrap();
3169+
///
3170+
/// assert_eq!(slice, &mut ['a', 'b']);
3171+
/// assert_eq!(tail, &mut ['c', 'd']);
3172+
/// ```
3173+
///
3174+
/// Getting `None` when `range` starts or ends outside of the slice:
3175+
///
3176+
/// ```
3177+
/// #![feature(slice_take)]
3178+
///
3179+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3180+
///
3181+
/// assert_eq!(None, slice.take_mut(5..));
3182+
/// assert_eq!(None, slice.take_mut(..5));
3183+
/// assert_eq!(None, slice.take_mut(..=4));
3184+
/// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd'];
3185+
/// assert_eq!(Some(expected), slice.take_mut(..4));
3186+
/// ```
3187+
#[inline]
3188+
#[unstable(feature = "slice_take", issue = "62280")]
3189+
pub fn take_mut<'a, R: OneSidedRange<usize>>(
3190+
self: &mut &'a mut Self,
3191+
range: R,
3192+
) -> Option<&'a mut Self> {
3193+
let (taking_front, split_index) = take_split_point(range)?;
3194+
if split_index > self.len() {
3195+
return None;
3196+
}
3197+
let original = crate::mem::take(self);
3198+
let (front, back) = original.split_at_mut(split_index);
3199+
if taking_front {
3200+
*self = back;
3201+
Some(front)
3202+
} else {
3203+
*self = front;
3204+
Some(back)
3205+
}
3206+
}
3207+
3208+
/// Takes the first element out of the slice.
3209+
///
3210+
/// Returns a reference pointing to the first element of the old slice.
3211+
///
3212+
/// Returns `None` if the slice is empty.
3213+
///
3214+
/// # Examples
3215+
///
3216+
/// ```
3217+
/// #![feature(slice_take)]
3218+
///
3219+
/// let mut slice: &[_] = &['a', 'b', 'c'];
3220+
/// let first = slice.take_first().unwrap();
3221+
///
3222+
/// assert_eq!(slice, &['b', 'c']);
3223+
/// assert_eq!(first, &'a');
3224+
/// ```
3225+
#[inline]
3226+
#[unstable(feature = "slice_take", issue = "62280")]
3227+
pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> {
3228+
self.take(..=0).map(|res| &res[0])
3229+
}
3230+
3231+
/// Takes the first element out of the mutable slice.
3232+
///
3233+
/// Returns a mutable reference pointing to the first element of the old slice.
3234+
///
3235+
/// Returns `None` if the slice is empty.
3236+
///
3237+
/// # Examples
3238+
///
3239+
/// ```
3240+
/// #![feature(slice_take)]
3241+
///
3242+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
3243+
/// let first = slice.take_first_mut().unwrap();
3244+
/// *first = 'd';
3245+
///
3246+
/// assert_eq!(slice, &['b', 'c']);
3247+
/// assert_eq!(first, &'d');
3248+
/// ```
3249+
#[inline]
3250+
#[unstable(feature = "slice_take", issue = "62280")]
3251+
pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
3252+
self.take_mut(..=0).map(|res| &mut res[0])
3253+
}
3254+
3255+
/// Takes the last element out of the slice.
3256+
///
3257+
/// Returns a reference pointing to the last element of the old slice.
3258+
///
3259+
/// Returns `None` if the slice is empty.
3260+
///
3261+
/// # Examples
3262+
///
3263+
/// ```
3264+
/// #![feature(slice_take)]
3265+
///
3266+
/// let mut slice: &[_] = &['a', 'b', 'c'];
3267+
/// let last = slice.take_last().unwrap();
3268+
///
3269+
/// assert_eq!(slice, &['a', 'b']);
3270+
/// assert_eq!(last, &'c');
3271+
/// ```
3272+
#[inline]
3273+
#[unstable(feature = "slice_take", issue = "62280")]
3274+
pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> {
3275+
self.take((self.len() - 1)..).map(|res| &res[0])
3276+
}
3277+
3278+
/// Takes the last element out of the mutable slice.
3279+
///
3280+
/// Returns a mutable reference pointing to the last element of the old slice.
3281+
///
3282+
/// Returns `None` if the slice is empty.
3283+
///
3284+
/// # Examples
3285+
///
3286+
/// ```
3287+
/// #![feature(slice_take)]
3288+
///
3289+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
3290+
/// let last = slice.take_last_mut().unwrap();
3291+
/// *last = 'd';
3292+
///
3293+
/// assert_eq!(slice, &['a', 'b']);
3294+
/// assert_eq!(last, &'d');
3295+
/// ```
3296+
#[inline]
3297+
#[unstable(feature = "slice_take", issue = "62280")]
3298+
pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
3299+
self.take_mut((self.len() - 1)..).map(|res| &mut res[0])
3300+
}
30623301
}
30633302

30643303
#[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
@@ -36,6 +36,7 @@
3636
#![feature(try_trait)]
3737
#![feature(slice_internals)]
3838
#![feature(slice_partition_dedup)]
39+
#![feature(slice_take)]
3940
#![feature(int_error_matching)]
4041
#![feature(array_value_iter)]
4142
#![feature(iter_partition_in_place)]

0 commit comments

Comments
 (0)