Skip to content

Commit

Permalink
Introduce <&[_]>::split_off and <&str>::split_off
Browse files Browse the repository at this point in the history
  • Loading branch information
nox committed Mar 28, 2018
1 parent 8aa27ee commit 14191c8
Show file tree
Hide file tree
Showing 6 changed files with 155 additions and 0 deletions.
2 changes: 2 additions & 0 deletions src/liballoc/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@
#![cfg_attr(not(test), feature(generator_trait))]
#![cfg_attr(test, feature(rand, test))]
#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(ascii_ctype)]
#![feature(box_into_raw_non_null)]
#![feature(box_patterns)]
Expand Down Expand Up @@ -112,6 +113,7 @@
#![feature(slice_get_slice)]
#![feature(slice_patterns)]
#![feature(slice_rsplit)]
#![feature(slice_split_off)]
#![feature(specialization)]
#![feature(staged_api)]
#![feature(str_internals)]
Expand Down
51 changes: 51 additions & 0 deletions src/liballoc/slice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1722,6 +1722,57 @@ impl<T> [T] {
// NB see hack module in this file
hack::into_vec(self)
}

/// Splits the slice into two at the given index.
///
/// Returns a newly slice. `self` contains elements `[0, at)`,
/// and the returned `Self` contains elements `[at, len)`.
///
/// # Panics
///
/// Panics if `at > len`.
///
/// # Examples
///
/// ```
/// #![feature(slice_split_off)]
///
/// let mut parisien: &[_] = &["baguette", "jambon", "beurre"];
/// let ingredients = parisien.split_off(1);
/// assert_eq!(parisien, &["baguette"]);
/// assert_eq!(ingredients, &["jambon", "beurre"]);
/// ```
#[unstable(feature = "slice_split_off", issue = "0")]
#[inline]
pub fn split_off<'a>(self: &mut &'a Self, at: usize) -> &'a [T] {
core_slice::SliceExt::split_off(self, at)
}

/// Splits the mutable slice into two at the given index.
///
/// Returns a newly mutable slice. `self` contains elements `[0, at)`,
/// and the returned `Self` contains elements `[at, len)`.
///
/// # Panics
///
/// Panics if `at > len`.
///
/// # Examples
///
/// ```
/// #![feature(slice_split_off)]
///
/// let mut parisien: &mut [_] = &mut ["baguette", "jambon", "beurre"];
/// let ingredients = parisien.split_off_mut(1);
/// ingredients[1] = "fromage";
/// assert_eq!(parisien, &["baguette"]);
/// assert_eq!(ingredients, &["jambon", "fromage"]);
/// ```
#[unstable(feature = "slice_split_off", issue = "0")]
#[inline]
pub fn split_off_mut<'a>(self: &mut &'a mut Self, at: usize) -> &'a mut [T] {
core_slice::SliceExt::split_off_mut(self, at)
}
}

#[lang = "slice_u8"]
Expand Down
61 changes: 61 additions & 0 deletions src/liballoc/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2249,6 +2249,67 @@ impl str {
let me = unsafe { self.as_bytes_mut() };
me.make_ascii_lowercase()
}

/// Splits the string slice into two at the given index.
///
/// Returns a new string slice. `self` contains bytes `[at, len)`, and
/// the returned string slice contains bytes `[at, len)`. `at` must be on
/// the boundary of a UTF-8 code point.
///
/// # Panics
///
/// Panics if `at` is not on a `UTF-8` code point boundary, or if it is
/// beyond the last code point of the string.
///
/// # Examples
///
/// ```
/// #![feature(slice_split_off)]
///
/// let mut best_baguette = "baguette de tradition";
/// let why_best = best_baguette.split_off(9);
/// assert_eq!(best_baguette, "baguette ");
/// assert_eq!(why_best, "de tradition");
/// ```
#[unstable(feature = "slice_split_off", issue = "0")]
#[inline]
pub fn split_off<'a>(self: &mut &'a Self, at: usize) -> &'a str {
core_str::StrExt::split_off(self, at)
}

/// Splits the mutable string slice into two at the given index.
///
/// Returns a new mutable string slice. `self` contains bytes `[0, at)`, and
/// the returned string slice contains bytes `[at, len)`. `at` must be on
/// the boundary of a UTF-8 code point.
///
/// To split immutable string slices instead, see the [`split_off`] method.
///
/// [`split_off`]: #method.split_off
///
/// # Panics
///
/// Panics if `at` is not on a UTF-8 code point boundary, or if it is
/// beyond the last code point of the string slice.
///
/// # Examples
///
/// Basic usage:
///
/// ```
/// #![feature(slice_split_off)]
///
/// let mut magritte_says = &mut *String::from("Ceci n'est pas une pipe.");
/// let it_is_not = magritte_says.split_off_mut(19);
/// it_is_not.make_ascii_uppercase();
/// assert_eq!(magritte_says, "Ceci n'est pas une ");
/// assert_eq!(it_is_not, "PIPE.");
/// ```
#[unstable(feature = "slice_split_off", issue = "0")]
#[inline]
pub fn split_off_mut<'a>(self: &mut &'a mut Self, at: usize) -> &'a mut str {
core_str::StrExt::split_off_mut(self, at)
}
}

/// Converts a boxed slice of bytes to a boxed string slice without checking
Expand Down
1 change: 1 addition & 0 deletions src/libcore/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,7 @@
#![deny(warnings)]

#![feature(allow_internal_unstable)]
#![feature(arbitrary_self_types)]
#![feature(asm)]
#![feature(associated_type_defaults)]
#![feature(attr_literals)]
Expand Down
20 changes: 20 additions & 0 deletions src/libcore/slice/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,12 @@ pub trait SliceExt {
fn sort_unstable_by_key<B, F>(&mut self, f: F)
where F: FnMut(&Self::Item) -> B,
B: Ord;

#[unstable(feature = "slice_split_off", issue = "0")]
fn split_off<'a>(self: &mut &'a Self, at: usize) -> &'a Self;

#[unstable(feature = "slice_split_off", issue = "0")]
fn split_off_mut<'a>(self: &mut &'a mut Self, at: usize) -> &'a mut Self;
}

// Use macros to be generic over const/mut
Expand Down Expand Up @@ -753,6 +759,20 @@ impl<T> SliceExt for [T] {
{
sort::quicksort(self, |a, b| f(a).lt(&f(b)));
}

#[inline]
fn split_off<'a>(self: &mut &'a Self, at: usize) -> &'a [T] {
let (rest, split) = self.split_at(at);
*self = rest;
split
}

#[inline]
fn split_off_mut<'a>(self: &mut &'a mut Self, at: usize) -> &'a mut [T] {
let (rest, split) = mem::replace(self, &mut []).split_at_mut(at);
*self = rest;
split
}
}

#[stable(feature = "rust1", since = "1.0.0")]
Expand Down
20 changes: 20 additions & 0 deletions src/libcore/str/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2181,6 +2181,10 @@ pub trait StrExt {
fn is_empty(&self) -> bool;
#[stable(feature = "core", since = "1.6.0")]
fn parse<T: FromStr>(&self) -> Result<T, T::Err>;
#[unstable(feature = "slice_split_off", issue = "0")]
fn split_off<'a>(self: &mut &'a Self, at: usize) -> &'a Self;
#[unstable(feature = "slice_split_off", issue = "0")]
fn split_off_mut<'a>(self: &mut &'a mut Self, at: usize) -> &'a mut Self;
}

// truncate `&str` to length at most equal to `max`
Expand Down Expand Up @@ -2501,6 +2505,22 @@ impl StrExt for str {

#[inline]
fn parse<T: FromStr>(&self) -> Result<T, T::Err> { FromStr::from_str(self) }

#[inline]
fn split_off<'a>(self: &mut &'a Self, at: usize) -> &'a str {
let (rest, split) = self.split_at(at);
*self = rest;
split
}

#[inline]
fn split_off_mut<'a>(self: &mut &'a mut Self, at: usize) -> &'a mut str {
// An empty slice of bytes is trivially valid UTF-8.
let empty = unsafe { from_utf8_unchecked_mut(&mut []) };
let (rest, split) = mem::replace(self, empty).split_at_mut(at);
*self = rest;
split
}
}

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

0 comments on commit 14191c8

Please sign in to comment.