Skip to content

Commit 36b8293

Browse files
cramertjDylan-DPC
authored andcommitted
Add take_... functions to slices
This adds the following associated functions to `[T]`: - take - take_mut - take_first - take_first_mut - take_last - take_last_mut
1 parent 9a12971 commit 36b8293

File tree

5 files changed

+362
-1
lines changed

5 files changed

+362
-1
lines changed

src/libcore/ops/mod.rs

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

189+
#[unstable(feature = "one_sided_range", issue = "69780")]
190+
pub use self::range::OneSidedRange;
191+
189192
#[unstable(feature = "try_trait", issue = "42327")]
190193
pub use self::r#try::Try;
191194

src/libcore/ops/range.rs

+18
Original file line numberDiff line numberDiff line change
@@ -891,3 +891,21 @@ impl<T> RangeBounds<T> for RangeToInclusive<&T> {
891891
Included(self.end)
892892
}
893893
}
894+
895+
/// `OneSidedRange` is implemented by Rust's built-in range types which
896+
/// are unbounded on one side. For example, `a..`, `..b` and `..=c` implement
897+
/// `OneSidedRange`, but `..`, `d..e`, and `f..=g` do not.
898+
///
899+
/// Types which implement `OneSidedRange<T>` must return `Bound::Unbounded`
900+
/// from exactly one of `RangeBounds::start_bound` and `RangeBounds::end_bound`.
901+
#[unstable(feature = "one_sided_range", issue = "69780")]
902+
pub trait OneSidedRange<T: ?Sized>: RangeBounds<T> {}
903+
904+
#[unstable(feature = "one_sided_range", issue = "69780")]
905+
impl<T> OneSidedRange<T> for RangeTo<T> where Self: RangeBounds<T> {}
906+
907+
#[unstable(feature = "one_sided_range", issue = "69780")]
908+
impl<T> OneSidedRange<T> for RangeFrom<T> where Self: RangeBounds<T> {}
909+
910+
#[unstable(feature = "one_sided_range", issue = "69780")]
911+
impl<T> OneSidedRange<T> for RangeToInclusive<T> where Self: RangeBounds<T> {}

src/libcore/slice/mod.rs

+240-1
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::isize;
3131
use crate::iter::*;
3232
use crate::marker::{self, Copy, Send, Sized, Sync};
3333
use crate::mem;
34-
use crate::ops::{self, FnMut, Range};
34+
use crate::ops::{self, Bound, FnMut, OneSidedRange, Range};
3535
use crate::option::Option;
3636
use crate::option::Option::{None, Some};
3737
use crate::ptr::{self, NonNull};
@@ -53,6 +53,24 @@ mod sort;
5353
// Extension traits
5454
//
5555

56+
/// Calculates the direction and split point of a one-sided range.
57+
///
58+
/// Helper for `take` and `take_mut` which returns a boolean
59+
/// indicating whether the front of the split is being taken
60+
/// (as opposed to the back), as well as a number indicating the
61+
/// index at which to split. Returns `None` if the split index would
62+
/// overflow `usize`.
63+
#[inline]
64+
fn take_split_point(range: impl OneSidedRange<usize>) -> Option<(bool, usize)> {
65+
Some(match (range.start_bound(), range.end_bound()) {
66+
(Bound::Unbounded, Bound::Excluded(i)) => (true, *i),
67+
(Bound::Unbounded, Bound::Included(i)) => (true, i.checked_add(1)?),
68+
(Bound::Excluded(i), Bound::Unbounded) => (false, i.checked_add(1)?),
69+
(Bound::Included(i), Bound::Unbounded) => (false, *i),
70+
_ => unreachable!(),
71+
})
72+
}
73+
5674
#[lang = "slice"]
5775
#[cfg(not(test))]
5876
impl<T> [T] {
@@ -2639,6 +2657,227 @@ impl<T> [T] {
26392657
{
26402658
self.iter().is_sorted_by_key(f)
26412659
}
2660+
2661+
/// Removes and returns the portion of the slice specified by `range`.
2662+
///
2663+
/// If the provided `range` starts or ends outside of the slice,
2664+
/// `None` is returned and the slice is not modified.
2665+
///
2666+
/// # Examples
2667+
///
2668+
/// Taking the first three items from a slice (via `..3`):
2669+
///
2670+
/// ```
2671+
/// #![feature(slice_take)]
2672+
///
2673+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
2674+
/// let mut first_three = slice.take(..3).unwrap();
2675+
///
2676+
/// assert_eq!(slice, &['d']);
2677+
/// assert_eq!(first_three, &['a', 'b', 'c']);
2678+
/// ```
2679+
///
2680+
/// Taking the tail of a slice starting at index two (via `2..`):
2681+
///
2682+
/// ```
2683+
/// #![feature(slice_take)]
2684+
///
2685+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
2686+
/// let mut tail = slice.take(2..).unwrap();
2687+
///
2688+
/// assert_eq!(slice, &['a', 'b']);
2689+
/// assert_eq!(tail, &['c', 'd']);
2690+
/// ```
2691+
///
2692+
/// Getting `None` when `range` starts or ends outside of the slice:
2693+
///
2694+
/// ```
2695+
/// #![feature(slice_take)]
2696+
///
2697+
/// let mut slice: &[_] = &['a', 'b', 'c', 'd'];
2698+
///
2699+
/// assert_eq!(None, slice.take(5..));
2700+
/// assert_eq!(None, slice.take(..5));
2701+
/// assert_eq!(None, slice.take(..=4));
2702+
/// let expected: &[char] = &['a', 'b', 'c', 'd'];
2703+
/// assert_eq!(Some(expected), slice.take(..4));
2704+
/// ```
2705+
#[inline]
2706+
#[unstable(feature = "slice_take", issue = "62280")]
2707+
pub fn take<'a, R: OneSidedRange<usize>>(self: &mut &'a Self, range: R) -> Option<&'a Self> {
2708+
let (taking_front, split_index) = take_split_point(range)?;
2709+
if split_index > self.len() {
2710+
return None;
2711+
}
2712+
let original = crate::mem::take(self);
2713+
let (front, back) = original.split_at(split_index);
2714+
if taking_front {
2715+
*self = back;
2716+
Some(front)
2717+
} else {
2718+
*self = front;
2719+
Some(back)
2720+
}
2721+
}
2722+
2723+
/// Removes and returns the portion of the mutable slice specified by `range`.
2724+
///
2725+
/// If the provided `range` starts or ends outside of the slice,
2726+
/// `None` is returned and the slice is not modified.
2727+
///
2728+
/// # Examples
2729+
///
2730+
/// Taking the first three items from a slice (via `..3`):
2731+
///
2732+
/// ```
2733+
/// #![feature(slice_take)]
2734+
///
2735+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
2736+
/// let mut first_three = slice.take_mut(..3).unwrap();
2737+
///
2738+
/// assert_eq!(slice, &mut ['d']);
2739+
/// assert_eq!(first_three, &mut ['a', 'b', 'c']);
2740+
/// ```
2741+
///
2742+
/// Taking the tail of a slice starting at index two (via `2..`):
2743+
///
2744+
/// ```
2745+
/// #![feature(slice_take)]
2746+
///
2747+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
2748+
/// let mut tail = slice.take_mut(2..).unwrap();
2749+
///
2750+
/// assert_eq!(slice, &mut ['a', 'b']);
2751+
/// assert_eq!(tail, &mut ['c', 'd']);
2752+
/// ```
2753+
///
2754+
/// Getting `None` when `range` starts or ends outside of the slice:
2755+
///
2756+
/// ```
2757+
/// #![feature(slice_take)]
2758+
///
2759+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c', 'd'];
2760+
///
2761+
/// assert_eq!(None, slice.take_mut(5..));
2762+
/// assert_eq!(None, slice.take_mut(..5));
2763+
/// assert_eq!(None, slice.take_mut(..=4));
2764+
/// let expected: &mut [_] = &mut ['a', 'b', 'c', 'd'];
2765+
/// assert_eq!(Some(expected), slice.take_mut(..4));
2766+
/// ```
2767+
#[inline]
2768+
#[unstable(feature = "slice_take", issue = "62280")]
2769+
pub fn take_mut<'a, R: OneSidedRange<usize>>(
2770+
self: &mut &'a mut Self,
2771+
range: R,
2772+
) -> Option<&'a mut Self> {
2773+
let (taking_front, split_index) = take_split_point(range)?;
2774+
if split_index > self.len() {
2775+
return None;
2776+
}
2777+
let original = crate::mem::take(self);
2778+
let (front, back) = original.split_at_mut(split_index);
2779+
if taking_front {
2780+
*self = back;
2781+
Some(front)
2782+
} else {
2783+
*self = front;
2784+
Some(back)
2785+
}
2786+
}
2787+
2788+
/// Takes the first element out of the slice.
2789+
///
2790+
/// Returns a reference pointing to the first element of the old slice.
2791+
///
2792+
/// Returns `None` if the slice is empty.
2793+
///
2794+
/// # Examples
2795+
///
2796+
/// ```
2797+
/// #![feature(slice_take)]
2798+
///
2799+
/// let mut slice: &[_] = &['a', 'b', 'c'];
2800+
/// let first = slice.take_first().unwrap();
2801+
///
2802+
/// assert_eq!(slice, &['b', 'c']);
2803+
/// assert_eq!(first, &'a');
2804+
/// ```
2805+
#[inline]
2806+
#[unstable(feature = "slice_take", issue = "62280")]
2807+
pub fn take_first<'a>(self: &mut &'a Self) -> Option<&'a T> {
2808+
self.take(..=0).map(|res| &res[0])
2809+
}
2810+
2811+
/// Takes the first element out of the mutable slice.
2812+
///
2813+
/// Returns a mutable reference pointing to the first element of the old slice.
2814+
///
2815+
/// Returns `None` if the slice is empty.
2816+
///
2817+
/// # Examples
2818+
///
2819+
/// ```
2820+
/// #![feature(slice_take)]
2821+
///
2822+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
2823+
/// let first = slice.take_first_mut().unwrap();
2824+
/// *first = 'd';
2825+
///
2826+
/// assert_eq!(slice, &['b', 'c']);
2827+
/// assert_eq!(first, &'d');
2828+
/// ```
2829+
#[inline]
2830+
#[unstable(feature = "slice_take", issue = "62280")]
2831+
pub fn take_first_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
2832+
self.take_mut(..=0).map(|res| &mut res[0])
2833+
}
2834+
2835+
/// Takes the last element out of the slice.
2836+
///
2837+
/// Returns a reference pointing to the last element of the old slice.
2838+
///
2839+
/// Returns `None` if the slice is empty.
2840+
///
2841+
/// # Examples
2842+
///
2843+
/// ```
2844+
/// #![feature(slice_take)]
2845+
///
2846+
/// let mut slice: &[_] = &['a', 'b', 'c'];
2847+
/// let last = slice.take_last().unwrap();
2848+
///
2849+
/// assert_eq!(slice, &['a', 'b']);
2850+
/// assert_eq!(last, &'c');
2851+
/// ```
2852+
#[inline]
2853+
#[unstable(feature = "slice_take", issue = "62280")]
2854+
pub fn take_last<'a>(self: &mut &'a Self) -> Option<&'a T> {
2855+
self.take((self.len() - 1)..).map(|res| &res[0])
2856+
}
2857+
2858+
/// Takes the last element out of the mutable slice.
2859+
///
2860+
/// Returns a mutable reference pointing to the last element of the old slice.
2861+
///
2862+
/// Returns `None` if the slice is empty.
2863+
///
2864+
/// # Examples
2865+
///
2866+
/// ```
2867+
/// #![feature(slice_take)]
2868+
///
2869+
/// let mut slice: &mut [_] = &mut ['a', 'b', 'c'];
2870+
/// let last = slice.take_last_mut().unwrap();
2871+
/// *last = 'd';
2872+
///
2873+
/// assert_eq!(slice, &['a', 'b']);
2874+
/// assert_eq!(last, &'d');
2875+
/// ```
2876+
#[inline]
2877+
#[unstable(feature = "slice_take", issue = "62280")]
2878+
pub fn take_last_mut<'a>(self: &mut &'a mut Self) -> Option<&'a mut T> {
2879+
self.take_mut((self.len() - 1)..).map(|res| &mut res[0])
2880+
}
26422881
}
26432882

26442883
#[lang = "slice_u8"]

src/libcore/tests/lib.rs

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#![feature(unwrap_infallible)]
4343
#![feature(leading_trailing_ones)]
4444
#![feature(const_forget)]
45+
#![feature(slice_take)]
4546

4647
extern crate test;
4748

0 commit comments

Comments
 (0)